Rails 5.1 + webpackでReact環境を作ってみたのでメモ

Rails 5.1からwebpackやYarnがサポートされフロントエンドの開発環境構築が非常にやりやすくなったと聞いたので自分でも試してみました。ただそんな中でも、そもそもRailsの知識に乏しいためもあってか割と苦労したので振り返りつつやり方を整理したいと思います。

## 環境
vagrantでCentOS7の仮想サーバーを建て、その中で作業していきます。
また、今回はrailsのgemをシステム全体に入れるのではなく、プロジェクト配下にのみ入れることを想定して環境を構築していきます。

```
$ cat /etc/redhat-release
CentOS Linux release 7.4.1708 (Core) 

$ rbenv -v
rbenv 1.1.1-28-gb943955

$ rbenv versions
* 2.4.3 (set by /home/vagrant/.rbenv/version)

$ ruby -v
ruby 2.4.3p205 (2017-12-14 revision 61247) [x86_64-linux]

$ bundler -v
Bundler version 1.16.1

$ nvm --version
0.33.8

$ node -v
v9.3.0

$ yarn -v
1.3.2

$ psql -V
psql (PostgreSQL) 10.1

```

## Railsプロジェクトの作成
まずはRailsプロジェクトのディレクトリを作成してそこに移動します

```
$ mkdir sample-app
$ cd sample-app
```

Gemfileを作成して、編集します

```
$ bundle init
Writing new Gemfile to /home/vagrant/sample-app/Gemfile

$ vi Gemfile
```

railsの行がコメントアウトになっているので#記号を削除して保存します

```ruby:Gemfile
# frozen_string_literal: true

source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

gem "rails"
```

Gemfileに記載されたgemをパスを指定してインストールします
bundlerについては次の記事に簡潔にまとめて頂けているので、まだ知識が曖昧という方はこれを機にぜひ読んでみてください。

* [システムのgemにrailsをインストールせずrails newする](https://qiita.com/youcune/items/222777415f00d19cccb4)
* [Bundler概要](https://qiita.com/hisonl/items/162f70e612e8e96dba50)

```
$ bundle install --path vendor/bundle
```

```
Fetching gem metadata from https://rubygems.org/..........
Fetching gem metadata from https://rubygems.org/.
Resolving dependencies...
Fetching rake 12.3.0
Installing rake 12.3.0
~~~ 省略 ~~~
Fetching rails 5.1.4
Installing rails 5.1.4
Bundle complete! 1 Gemfile dependency, 38 gems now installed.
Bundled gems are installed into `./vendor/bundle`
```

これで `rails` コマンドが使えるようになったので、 `rails new` でアプリを作っていきます。
話の本筋とはズレますが、React導入に必要なwebpackオプションに加えて、DBをデフォルトのSQLiteからPostgreSQLに変更するためのオプションも渡しています。
ちなみに `--webpack=react` というオプションについて先に解説すると、裏で

```
bundle exec rails webpacker:install 
bundle exec rails webpacker:install:react
```
という2つのコマンドを行ってくれるものです。

```
$ bundle exec rails new . --webpack=react --database=postgresql
```

```
       exist  
      create  README.md
      create  Rakefile
      create  config.ru
      create  .gitignore
    conflict  Gemfile
Overwrite /home/vagrant/sample-app/Gemfile? (enter "h" for help) [Ynaqdh] 
```

Gemfileを上書きしてもいいかと聞かれますので y を入力してEnterを押します。

```
       force  Gemfile
         run  git init from "."
Reinitialized existing Git repository in /home/vagrant/sample-app/.git/
      create  app
      create  app/assets/config/manifest.js
      create  app/assets/javascripts/application.js

~~~ 省略 ~~~

         run  bundle install

~~~ 省略 ~~~

Fetching ffi 1.9.21
Installing ffi 1.9.21 with native extensions
Gem::Ext::BuildError: ERROR: Failed to build gem native
extension.

~~~ 省略 ~~~

An error occurred while installing ffi (1.9.21),
and Bundler cannot continue.
Make sure that `gem install ffi -v '1.9.21'` succeeds
before bundling.

In Gemfile:
selenium-webdriver was resolved to 3.9.0, which depends
on
    childprocess was resolved to 0.8.0, which depends on
      ffi
       rails  webpacker:install

~~~ 省略 ~~~
```

bundle install の途中でエラーが出てしまいました。

エラーの内容を見てみると、 ffi という gem のインストールに失敗しているようです。
また、ffi は webpacker:install コマンドに必要なようで、こちらも後で実行し直す必要がありそうです。

解決方法を探るために rubygems で ffi を検索してみます。

[https://rubygems.org/gems/ffi](https://rubygems.org/gems/ffi)

見てみると、February 06, 2018 (2018/02/06)に最新バージョンが出ているようです。
（執筆している現在は2018/02/10）
ひとまずバージョンを一つ前のものを指定してもう一度インストールしてみます。
バージョンを指定してインストールするために、Gemfileに次の１行を追加します。

```
$ vi Gemfile
```

```ruby:Gemfile
gem 'ffi', '1.9.18'
```

保存したらもういちど bundler で gem をインストールします。

```
$ bundle install
```

```
The dependency tzinfo-data (>= 0) will be unused by any of the platforms Bundler is installing for. Bundler is installing for ruby but the dependency is only for x86-mingw32, x86-mswin32, x64-mingw32, java. To add those platforms to the bundle, run `bundle lock --add-platform x86-mingw32 x86-mswin32 x64-mingw32 java`.
Fetching gem metadata from https://rubygems.org/.........
Fetching gem metadata from https://rubygems.org/.
Resolving dependencies....
Using rake 12.3.0

~~~ 省略 ~~~

Fetching ffi 1.9.18
Installing ffi 1.9.18 with native extensions
Fetching childprocess 0.8.0
Installing childprocess 0.8.0

~~~ 省略 ~~~

Fetching webpacker 3.2.1
Installing webpacker 3.2.1
Bundle complete! 18 Gemfile dependencies, 72 gems now installed.
Bundled gems are installed into `./vendor/bundle`
```

無事にgemのインストールが完了しました。

それでは次に `--webpack=react` オプションによって裏で実行してもらえる予定だったのに、gem のインストールに失敗したせいで実行されることのなかったコマンドを手動で実行していきます。

＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝
※ ちなみに先ほど `rails　new` コマンドをする際には先頭に `bundle exec` をつけて実行しましたが、 `rails new` コマンドを実行してRailsプロジェクトを作成したあとはbinディレクトリ配下にrailsコマンドが準備されるため、 `bundle exec rails` の代わりに `bin/rails` としても実行できるようになります。

```
$ ls bin/
bundle  rails  rake  setup  update  yarn
```

ただし、混乱を避けるために本記事中では今後も `bundle exec` としてrailsコマンドを実行していきます。
＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝

```
$ bundle exec rails webpacker:install
```

```
      create  config/webpacker.yml
Copying webpack core config
      create  config/webpack
      create  config/webpack/development.js
      create  config/webpack/environment.js
      create  config/webpack/production.js
      create  config/webpack/test.js
Copying .postcssrc.yml to app root directory
      create  .postcssrc.yml

~~~ 省略 ~~~

Done in 41.74s.
Webpacker successfully installed 🎉 🍰
```

webpacker のインストールが完了しました。
続けて React のインストールです。

```
$ bundle exec rails webpacker:install:react
```

```
Webpacker is installed 🎉 🍰
Using /home/vagrant/sample-app/config/webpacker.yml file for setting up webpack paths
Copying react preset to your .babelrc file
Copying react example entry file to /home/vagrant/sample-app/app/javascript/packs

~~~ 省略 ~~~

Done in 46.42s.
Webpacker now supports react.js 🎉
```

webpack、Reactのインストールが完了しました。
binディレクトリの中を確認すると `webpack` `webpack-dev-server` コマンドが新たに追加されていることが確認できます。

```
$ ls bin/
bundle  rails  rake  setup  update  webpack  webpack-dev-server  yarn
```

以上でRails、webpack、Reactの入ったRailsプロジェクトの完成です。

## 動作確認
まずはRailsが動作しているかを確認するためにサーバーを起動します

```
$ bundle exec rails s
```

サーバーを起動したらブラウザのアドレス欄に `localhost:3000` と入力してページを開きます。
次のような画面が出ればRailsは動作しています。

（2018/4/11 追記）
vagrantfileに次の一行を追加してホストOSとゲストOSでポートフォワーディングする必要があります。

```
    config.vm.network "forwarded_port", guest: 3000, host: 3000
```

![スクリーンショット 2018-02-11 15.12.42.png](https://qiita-image-store.s3.amazonaws.com/0/204438/6c1f9b43-6499-9117-5356-fa78e77738d0.png)

Railsの動作確認ができたら次はReactの動作確認をします。
Railsサーバーは Ctrl + C で一旦止めておきます。

Reactの動作確認をするには一手間必要になります。
まずはHelloコントローラーを作成します。

```
$ bundle exec rails g controller hello index
```

次にルーティングを書き換えます。

```
$ vi config/routes.rb
```

```ruby:config/routes.rb
Rails.application.routes.draw do
  root to: 'hello#index'
end
```

レイアウトファイル `app/views/layouts/application.html.erb` を編集します。
JavaScriptをインクルードするヘルパーメソッドを `javascript_include_tag` から `javascript_pack_tag` に変更します。

```
$ vi app/views/layouts/application.html.erb
```

```erb:app/views/layouts/application.html.erb
~~~ 省略 ~~~

    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>

~~~ 省略 ~~~
```

`javascript_pack_tag` は、先ほどインストールしたの　webpacker　という　gem　が提供するヘルパーメソッドです。
このメソッドを使用すると、 JavaScript が `app/assets/javascripts/` ではなく、 `app/javascript/packs/` 配下のものがインクルードされるようにRailsの動作が変わります。

React をインストールすると `app/javascript/packs/` にサンプルの `hello_sample.jsx` が作成されています。

```
$ ls app/javascript/packs/
application.js  hello_react.jsx
```

このサンプルファイルを読み込むように次のように設定を変更します。

```
$ vi app/javascript/packs/application.js 
```

```js:app/javascript/packs/application.js 
~~~ 省略 ~~~

console.log('Hello World from Webpacker')
require('./hello_react.jsx')    // この行を追加
```

jsx ファイルをコンパイルして js ファイルを作成します。
コンパイルをするためには次のコマンドを実行します。

```
$ bin/webpack-dev-server
Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.
```

何やらエラーが出ているのでメッセージ通りにコマンドを実行します。

```
$ bundle binstubs bundler --force
```

再度コンパイルを実行します。

```
$ bin/webpack-dev-server
 10% building modules 2/2 modules 0 active                                         
Project is running at http://localhost:3035/
webpack output is served from /packs/
Content not from webpack is served from /home/vagrant/sample-app3/public/packs

~~~ 省略 ~~~

webpack: Compiled successfully.
```

コンパイルに成功し、 webpack-dev-server　が起動しました。
この状態でもう一つコンソールを起動してRailsプロジェクトのルート階層に移動します。
※ Macの場合 command + t でターミナルのタブを複製できます。再度vagrant sshで仮想サーバーに接続します。

```
$ cd sample-app
```

Railsサーバーを起動します。

```
$ bundle exec rails s
```

ブラウザで localhost:3000 にアクセスし、「Hello React!」が表示されれば Rails 上で React が動いています。

![スクリーンショット 2018-02-11 16.08.36.png](https://qiita-image-store.s3.amazonaws.com/0/204438/0e6f3963-5545-cfc8-1309-f56695b5e6db.png)

## 参考

* [システムのgemにrailsをインストールせずrails newする](https://qiita.com/youcune/items/222777415f00d19cccb4)
* [Bundler概要](https://qiita.com/hisonl/items/162f70e612e8e96dba50)
* [Rails 5.1でrails-react-webpack環境を作って動かしてみる](https://permanent-til-me.ssl-netowl.jp/archives/1574)
* [Rails 5.1でReact.js連携アプリを構築してみよう](https://codezine.jp/article/detail/10209)
* [Rails5.1でReact を動かそう【webpackerによる環境構築編】](https://bagelee.com/programming/ruby-on-rails/rails5-1-react-webpack/)
* [Rails 5.1のwebpack (gem無し)を使ってReact, Redux, Material-UIの環境構築](http://tango-ruby.hatenablog.com/entry/2017/05/18/001120)
* [Vue.jsとRailsでTODOアプリのチュートリアルみたいなものを作ってみた](https://qiita.com/naoki85/items/51a8b0f2cbf949d08b11)