Rails5.1.0 Beta1でVue.jsアプリケーションを作る

Rails5.1でフロントエンド周りのサポートが強化されたとのことで、試してみました。
既に試していた方の記事([Railsが5.1になることでフロントエンドの開発が本当に楽しくなりました](http://www.chirashiura.com/entry/2017/02/26/013532))があったのでそれを参考に。
それでもちょこちょこハマった箇所があったのでその記録です。


OSはMacOS、バージョン情報は以下の通り。

```
$ bin/rake about
Running via Spring preloader in process 2380
About your application's environment
Rails version             5.1.0.beta1
Ruby version              2.4.0-p-1 (x86_64-darwin15)
RubyGems version          2.6.6
Rack version              2.0.1
JavaScript Runtime        Node.js (V8)
~省略~
```

## 5.1.0.beta1のインストール

```bash
gem install rails -v 5.1.0.beta1
```

## アプリケーションの新規作成

```bash
rails new rails5.1-beta1-app --webpack=vue
```

## webpackerのインストール

```
bin/rake webpacker:install:vue
```

```
Running via Spring preloader in process 61068
Couldn't automatically update module resolution in /Users/jacoyutorius/Work/rail5.1-beta1-app/config/webpack/shared.js. Please set resolve { alias:{ 'vue$':'vue/dist/vue.common.js' } }.
Couldn't automatically update url-loader in /Users/jacoyutorius/Work/rail5.1-beta1-app/config/webpack/shared.js. Please set { test: /.png$/, loader: 'url-loader?mimetype=image/png' }.
Couldn't automatically update vue-loader in /Users/jacoyutorius/Work/rail5.1-beta1-app/config/webpack/shared.js. Please set { test: /.vue$/, loader: 'vue-loader', options: { loaders: { 'scss': 'vue-style-loader!css-loader!sass-loader', 'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax'}}}.
Copying the Vue example to app/javascript/packs/vue
Yarn executable was not detected in the system.
Download Yarn at https://yarnpkg.com/en/docs/install
```

npmではなく、yarnでnodeのパッケージを管理するらしいのでyarnをインストールします。

```
brew update
brew install yarn
```

```
bundle exec rails webpacker:install:vue
```

## webpackのインストール

bin/webpackを実行したところ、node_modules/webpackが無いと怒られたのでyarnを使ってwebpack関連をインストールしました。


```bash
bin/yarn add --dev webpack webpack-dev-server webpack-merge
```

webpack-dev-serverをインストール後に表示されるワーニングに従います。


```bash
bin/webpack-dev-server
Warning: if you want to use webpack-dev-server, you need to tell Webpacker to serve asset packs from it. Please set config.x.webpacker[:dev_server_host] in config/environments/development.rb.
```

webpack-dev-serverを使う場合に、dev-serverのURLを設定せよとのことです。
development.rbでコメントアウトされている箇所よりコメントを外します。

**config/environments/development.rb**

```ruby
Rails.application.configure do
  # Make javascript_pack_tag load assets from webpack-dev-server.
  config.x.webpacker[:dev_server_host] = "http://localhost:8080"
```

## path-complete-extname、babel-core、babel-loader

この辺省略しますが、このパッケージが無い！というエラーメッセージに従ってyarn installしています。

```
bin/yarn add --dev path-complete-extname babel-core babel-loader
```

## 「Couldn't find preset "latest" relative to directory」エラー

ぱっと見では原因不明なエラーがでました。


```
ERROR in ./app/javascript/packs/hello_vue.js
Module build failed: Error: Couldn't find preset "latest" relative to directory "/Users/jacoyutorius/Work/rail5.1-beta1-app/app/javascript/packs"
    at /Users/jacoyutorius/Work/rail5.1-beta1-app/node_modules/babel-core/lib/transformation/file/options/option-manager.js:293:19
    at Array.map (native)
    at OptionManager.resolvePresets (/Users/jacoyutorius/Work/rail5.1-beta1-app/node_modules/babel-core/lib/transformation/file/options/option-manager.js:275:20)
    at OptionManager.mergePresets (/Users/jacoyutorius/Work/rail5.1-beta1-app/node_modules/babel-core/lib/transformation/file/options/option-manager.js:264:10)
    at OptionManager.mergeOptions (/Users/jacoyutorius/Work/rail5.1-beta1-app/node_modules/babel-core/lib/transformation/file/options/option-manager.js:249:14)
    at OptionManager.init (/Users/jacoyutorius/Work/rail5.1-beta1-app/node_modules/babel-core/lib/transformation/file/options/option-manager.js:368:12)
    at File.initOptions (/Users/jacoyutorius/Work/rail5.1-beta1-app/node_modules/babel-core/lib/transformation/file/index.js:216:65)
    at new File (/Users/jacoyutorius/Work/rail5.1-beta1-app/node_modules/babel-core/lib/transformation/file/index.js:139:24)
    at Pipeline.transform (/Users/jacoyutorius/Work/rail5.1-beta1-app/node_modules/babel-core/lib/transformation/pipeline.js:46:16)
    at transpile (/Users/jacoyutorius/Work/rail5.1-beta1-app/node_modules/babel-loader/lib/index.js:46:20)
 @ multi (webpack)-dev-server/client?http://localhost:8080 ./app/javascript/packs/hello_vue.js

ERROR in ./app/javascript/packs/application.js
Module build failed: Error: Couldn't find preset "latest" relative to directory "/Users/jacoyutorius/Work/rail5.1-beta1-app/app/javascript/packs"
    at /Users/jacoyutorius/Work/rail5.1-beta1-app/node_modules/babel-core/lib/transformation/file/options/option-manager.js:293:19
    at Array.map (native)
    at OptionManager.resolvePresets (/Users/jacoyutorius/Work/rail5.1-beta1-app/node_modules/babel-core/lib/transformation/file/options/option-manager.js:275:20)
    at OptionManager.mergePresets (/Users/jacoyutorius/Work/rail5.1-beta1-app/node_modules/babel-core/lib/transformation/file/options/option-manager.js:264:10)
    at OptionManager.mergeOptions (/Users/jacoyutorius/Work/rail5.1-beta1-app/node_modules/babel-core/lib/transformation/file/options/option-manager.js:249:14)
    at OptionManager.init (/Users/jacoyutorius/Work/rail5.1-beta1-app/node_modules/babel-core/lib/transformation/file/options/option-manager.js:368:12)
    at File.initOptions (/Users/jacoyutorius/Work/rail5.1-beta1-app/node_modules/babel-core/lib/transformation/file/index.js:216:65)
    at new File (/Users/jacoyutorius/Work/rail5.1-beta1-app/node_modules/babel-core/lib/transformation/file/index.js:139:24)
    at Pipeline.transform (/Users/jacoyutorius/Work/rail5.1-beta1-app/node_modules/babel-core/lib/transformation/pipeline.js:46:16)
    at transpile (/Users/jacoyutorius/Work/rail5.1-beta1-app/node_modules/babel-loader/lib/index.js:46:20)
 @ multi (webpack)-dev-server/client?http://localhost:8080 ./app/javascript/packs/application.js
webpack: Failed to compile.
```

エラーメッセージがわなわなと出ていますが、とりあえず"latest"というキーワードでヒットしたshared.jsを見てみます。
babel-preset-es2015をインストールして、options周りをちょっと変更しました。

```
bin/yarn add --dev babel-preset-es2015
```

**/config/webpack/shared.js**

```js
  module: {
    rules: [
      {
        test: /.vue$/, loader: 'vue-loader',
        options: {
          loaders: { 'scss': 'vue-style-loader!css-loader!sass-loader', 'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax'}
        }
      },
      { test: /.png$/, loader: 'url-loader?mimetype=image/png'},
      { test: /\.coffee(\.erb)?$/, loader: "coffee-loader" },
      {
        test: /\.js(\.erb)?$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        options: {
          presets: [
            // [ 'latest', { 'es2015': { 'modules': false } } ]
            [ 'es2015' ] //このように変更
          ]
        }
      },
      {
```

## 「Vue packages version mismatch」

babel関連のエラーは解消しましたが、今度はvue.jsの周りでエラーが。

```
ERROR in ./app/javascript/packs/app.vue
Module build failed: Error:

Vue packages version mismatch:

- vue@2.1.10
- vue-template-compiler@2.2.1

This may cause things to work incorrectly. Make sure to use the same version for both.
If you are using vue-loader@>=10.0, simply update vue-template-compiler.
If you are using vue-loader@<10.0 or vueify, re-installing vue-loader/vueify should bump vue-template-compiler to the latest.

    at Object.<anonymous> (/Users/jacoyutorius/Work/rail5.1-beta1-app/node_modules/vue-template-compiler/index.js:8:9)
    at Module._compile (module.js:541:32)
    at Object.Module._extensions..js (module.js:550:10)
    at Module.load (module.js:458:32)
    at tryModuleLoad (module.js:417:12)
    at Function.Module._load (module.js:409:3)
    at Module.require (module.js:468:17)
    at require (internal/module.js:20:19)
    at Object.<anonymous> (/Users/jacoyutorius/Work/rail5.1-beta1-app/node_modules/vue-loader/lib/parser.js:1:78)
    at Module._compile (module.js:541:32)
 @ ./app/javascript/packs/hello_vue.js 7:11-31
 @ multi (webpack)-dev-server/client?http://localhost:8080 ./app/javascript/packs/hello_vue.js
webpack: Failed to compile.
^C
```


**package.json**

エラーメッセージに従ってvueとvue-template-compilerのバージョンを同じものに修正。
node_modulesとyarn.lockを削除した上で再度bin/yarn install。

```json
  "dependencies": {
    "axios": "^0.15.3",
    "css-loader": "^0.26.2",
    "node-sass": "^4.5.0",
    "sass-loader": "^6.0.2",
    "url-loader": "^0.5.8",
    "vue": "2.1.10",
    "vue-loader": "11.1.3",
    "vue-template-compiler": "2.1.10"
  },
```

これでやっとwebpack-dev-serverが起動しました。

## Foreman

rails serverとwebpack-dev-serverを別々に起動するのは面倒なので、foremanをインストールしてrails serverとwebpack-dev-serverを一緒に起動してしまいます。

**Procfile**

```ruby
web: bundle exec rails s
webpack-watcher: ./bin/webpack-dev-server
```

```bash
foreman start
```

```bash
01:25:17 web.1             | started with pid 3461
01:25:17 webpack-watcher.1 | started with pid 3462
01:25:54 webpack-watcher.1 | Project is running at http://localhost:8080/
01:25:54 webpack-watcher.1 | webpack output is served from /
01:25:54 webpack-watcher.1 | Content not from webpack is served from /Users/jacoyutorius/Work/rail5.1-beta1-app/public/packs
01:26:10 web.1             | => Booting Puma
01:26:10 web.1             | => Rails 5.1.0.beta1 application starting in development on http://localhost:5000
01:26:10 web.1             | => Run `rails server -h` for more startup options
01:26:12 web.1             | Puma starting in single mode...
01:26:12 web.1             | * Version 3.7.1 (ruby 2.4.0-p-1), codename: Snowy Sagebrush
01:26:12 web.1             | * Min threads: 5, max threads: 5
01:26:12 web.1             | * Environment: development
01:26:12 web.1             | * Listening on tcp://localhost:5000
01:26:12 web.1             | Use Ctrl-C to stop

~省略~
```

Foremanを初めて使ったんですが、これ使うと3000番ではなく5000番で起動する様子。

http://localhost:5000/


## ルート用コントローラの作成

あとはいつものrailsです。

```
bin/rails g controller home index
```

**config/routes.rb**

```
Rails.application.routes.draw do
  root "home#index"
end

```

**app/views/home/index.html.erb**

javascript_pack_tagというヘルパを使うと引数に指定したvueのコンポーネントを設置するhtmlを生成してくれるようです。

```
<h1>Home#index</h1>
<p>Find me in app/views/home/index.html.erb</p>

<%= javascript_pack_tag 'hello_vue' %>
```

![Rail51Beta1App.png](https://qiita-image-store.s3.amazonaws.com/0/8607/cdd2b43a-6e3e-0ff9-3e63-858140be423d.png "Rail51Beta1App.png")


とりあえずこれでRailsのデフォルトページが表示できました。
今度はbulmaなどのCSSフレームワークをインストールしてみようと思います。

## 感想

それにしてもまたいろんなrakeタスクが増えたなぁという印象です（これがrails wayというものか）
個人的にはフロントエンドはあちらの流儀で管理してサーバーサイドとは完全に分離したほうが良さそうだなぁと思ってた矢先でしたが、
コマンド一発でちゃんと定義されたwebpackのボイラープレートが生成されるのは良いですね。


## 参考

大変役に立ちました、ありがとうございます。

http://www.chirashiura.com/entry/2017/02/26/013532