Rails 5.1でrails-react-webpack環境を作って動かしてみる


Ruby on Rails 5.1から、webpackをrailsでサポートするgem「webpacker」が導入されました。

5.0までのRailsのjavascriptの標準はjQuery(+CoffeeScript)であり、2017年現在SPAの隆盛もあってかやや時代遅れ感が否めないものでした。

これまで、webpack及びreactをrailsに導入するには、サードパーティ製のgemを使用したり、自分でpackage.json及びwebpack.config.jsをガリガリ書く必要がありました。

しかし、webpackerの導入により、簡単にフロントエンドの最新のアーキテクチャを低コストでRailsに乗せる事ができるようになりました。

新しくRailsプロジェクトを開始するときには、これを使わない手はないでしょう。

本記事では、新しくRailsプロジェクトを作成し、webpackerを設定してReact ComponentがRails上で動作するまでの手順を解説します。

動作環境

  • Ruby 2.4.1
  • Rails 5.1.4
  • node.js 8.3.0
  • yarn 1.0.1

手順概要

  1. rails newプロジェクトを作成
  2. webpacker周りの初期設定をする
  3. Controllerのサンプルコードを記述する
  4. Reactソースを記述
  5. トランスパイル
  6. View側でトランスパイルされたJavaScriptを読み込む
  7. rails serverで動作確認

1. rails new プロジェクトを作成

まずはrails newしましょう。

webpackerの設定を活かすには、以下のように、webpackオプションを付加します。

rails new sample --webpack=react

作成されたプロジェクトのGemfileを見てみます。

source 'https://rubygems.org'

git_source(:github) do |repo_name|
  repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/")
  "https://github.com/#{repo_name}.git"
end


# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 5.1.4'
# Use sqlite3 as the database for Active Record
gem 'sqlite3'
# Use Puma as the app server
gem 'puma', '~> 3.7'
# Use SCSS for stylesheets
gem 'sass-rails', '~> 5.0'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'
# Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker
gem 'webpacker'
# See https://github.com/rails/execjs#readme for more supported runtimes
# gem 'therubyracer', platforms: :ruby

# Use CoffeeScript for .coffee assets and views
gem 'coffee-rails', '~> 4.2'
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
gem 'turbolinks', '~> 5'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.5'
# Use Redis adapter to run Action Cable in production
# gem 'redis', '~> 3.0'
# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'

# Use Capistrano for deployment
# gem 'capistrano-rails', group: :development

group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
  # Adds support for Capybara system testing and selenium driver
  gem 'capybara', '~> 2.13'
  gem 'selenium-webdriver'
end

group :development do
  # Access an IRB console on exception pages or by using <%= console %> anywhere in the code.
  gem 'web-console', '>= 3.3.0'
  gem 'listen', '>= 3.0.5', '< 3.2'
  # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
  gem 'spring'
  gem 'spring-watcher-listen', '~> 2.0.0'
end

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

webpackerのgemが依存関係に追加されています。

2.webpacker周りの初期設定をする

webpackerのデフォルト設定を自動で生成するコマンドが提供されているので、使ってみましょう。(※webpackerの実行には、yarnの0.25.2以上が必要です。)

bundle exec rails webpacker:install
bundle exec rails webpacker:install:react # 前の行のコマンドを実行してから実行すること。一気にやろうとするとうまくいかない

これで、webpackerを使用する準備が整いました。

なお、webpackerの設定はconfig/webpacker.yml及び、config/webpack/以下に存在するので、自分好みに設定する場合はこれらのファイルを編集してください。

ついでに、config.generatorを編集して、CoffeeScriptの自動生成をオフにします。

config.generators do |g|
  # ...generatorの設定
  g.javascripts     false
end

参考:Rails newでRailsプロジェクトを作ったらconfig.generatorsを設定しよう

gemからもcoffee-railsの行を削除して、coffeescriptからは完全にお別れしましょう。

# Use CoffeeScript for .coffee assets and views
gem 'coffee-rails', '>= 4.2' # この行を削除

これで、webpack-reactを使用する基盤が整いました。

3.Controllerのサンプルコードを記述する

いつものscaffoldでcontrollerを作成しましょう。

今回はサンプルなので、HogeController#indexを作成します。

bundle exec rails g controller Hoge index

4. Reactソースを記述

実際にReactソースを記述していきましょう。

webpackerのトランスパイル対象となるのは、デフォルトではapp/javascript/packs 直下のjs(jsx)ファイルです。

なので、例えば以下のようにパッケージ構成を組んだ場合、

assetsに配置されるのは、applicaction.jsとhello_react.jsxのトランスパイルされたファイルであり、src/components/SampleForm.jsxはファイルとしてはアウトプットされません。

エントリ元のjsファイルから適切にimportすることで、依存関係をwebpackerが解決してくれます。

この特性を利用して、packs/以下のサブディレクトリは開発者の自由にパッケージ設計をすることができます。

上記の例では、packs/src/componentsにReact Componentを作成するような設計にしています。

SampleForm.jsxをhello_react.jsxでimportする感じですね。

以下のような簡単なReactComponentを書いてみます。

hello_react.jsx

import React from 'react'
import ReactDOM from 'react-dom'
import SampleForm from './src/components/SampleForm'

ReactDOM.render(
    <SampleForm/>,
    document.getElementById('sample')
);

sample_form.jsx


import React from 'react';

export default class SampleForm extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      text: ''
    };
    this.onChange=this.onChange.bind(this);
  }

  onChange(e){
    this.setState({
      text:e.target.value
    });
  }

  render() {
    return (
        <div>
          <input type="text" onChange={this.onChange} value={this.state.text} />
          <p>{this.state.text}</p>
        </div>
    );
  }

}

5.トランスパイル実行

ソースをwebpackでトランスパイルするには、以下のコマンドを実行します。

./bin/webpack

また、webpack-dev-serverを立ち上げるには、

./bin/webpack-web-server

に記述します。

webpack-dev-serverを立ち上げていると、jsファイルの変更を検知して自動的にトランスパイルを再実行し、画面を再ロードしてくれます。便利ですね!

6.View側でトランスパイルされたjsファイルを読み込む

View側でjavascriptを読み込むには、javascript_pack_tag ヘルパーを使用します。

従来のRailsでは、javascript_include_tagヘルパーでしたが、微妙にHelper名が変わっていることに注意しましょう。

app/views/hoge/index.html.erb

<h1>Hoge#index</h1>
<p>Find me in app/views/hoge/index.html.erb</p>
<div id="sample"></div>
<%= javascript_pack_tag 'hello_react' %>

7.rails serverで動作確認

bundle exec rails s

localhost:3000/hoge/index にアクセスして動作確認をします。

inputフォームに文字を入力すると、すぐ下のpタグ要素も連動して変わります。

ReactComponentが正しく動作していますね。

参考にした記事