Posted at

react_on_rails導入

More than 3 years have passed since last update.

react_on_rails

RailsでReactを使う場合に検討するgemとして、導入が容易なのはreact-rails。一方、react_on_railsはWebpack, Babel, React, Redux, React-RouterなどのモダンJSスタックをRailsと密結合にならない形で導入したい状況を想定しているようだ。

react_on_railsを使った新規アプリをHerokuへデプロイするフローを確認する。


環境


  • Ruby 2.2.3

  • Rails 4.2


ローカルで動かす


空のアプリ作成

$ rails new APP_NAME --database=postgresql

$ cd APP_NAME
$ rake db:create
$ rails s

$ git init

$ git add .
$ git commit -m'initial'


react_on_rails導入

+gem "react_on_rails", "~> 6"

$ bundle


git commit

ここでの注意点は、次に実行するrails g react_on_rails:installは、git statusの結果が綺麗になっていないとこける仕様になっていること。なので一旦commitする必要がある。

$ git status

$ git add .
$ git commit -m'install react_on_rails'


react_on_rails起動

$ rails g react_on_rails:install

サンプルコードを含めていろいろファイルが自動修正・作成される。

On branch master

Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)

modified: .gitignore
modified: Gemfile
modified: Gemfile.lock
modified: app/assets/javascripts/application.js
modified: config/initializers/assets.rb
modified: config/routes.rb

Untracked files:
(use "git add <file>..." to include in what will be committed)

Procfile.dev
app/controllers/hello_world_controller.rb
app/views/hello_world/
client/
config/initializers/react_on_rails.rb
package.json

少し複雑なので、主なファイルを追っておく。


Webpackでコンポーネントをバンドルするための変更


package.json

{

"name": "react-webpack-rails-tutorial",
"version": "0.0.1",
"engines": {
"node": "5.10.0",
"npm": "3.5.0"
},
"scripts": {
"postinstall": "cd client && npm install",
"rails-server": "echo 'visit http://localhost:3000/hello_world' && foreman start -f Procfile.dev",
"test": "rspec"
}
}


Procfile.dev

web: rails s -p 3000

client: sh -c 'rm app/assets/webpack/* || true && cd client && npm run build:development'


client/package.json

{

"name": "react-webpack-rails-tutorial",
"version": "0.0.1",
"engines": {
"node": "5.10.0",
"npm": "3.5.0"
},
"scripts": {
"build:test": "webpack --config webpack.config.js",
"build:production": "NODE_ENV=production webpack --config webpack.config.js",
"build:development": "webpack -w --config webpack.config.js"
},
..


client/webpack.config.js

const webpack = require('webpack');

const path = require('path');

const devBuild = process.env.NODE_ENV !== 'production';
const nodeEnv = devBuild ? 'development' : 'production';

const config = {
entry: [
'es5-shim/es5-shim',
'es5-shim/es5-sham',
'babel-polyfill',
'./app/bundles/HelloWorld/startup/HelloWorldApp',
],

output: {
filename: 'webpack-bundle.js',
path: '../app/assets/webpack',
},

..



Reactコンポーネントとエントリポイント


client/app/bundles/HelloWorld/startup/HelloWorldApp.jsx

import React from 'react';

import ReactOnRails from 'react-on-rails';

import HelloWorld from '../containers/HelloWorld';

const HelloWorldApp = (props) => (
<HelloWorld {...props} />
);

// This is how react_on_rails can see the HelloWorldApp in the browser.
ReactOnRails.register({ HelloWorldApp });



client/app/bundles/HelloWorld/containers/HelloWorld.jsx

import React, { PropTypes } from 'react';

import HelloWorldWidget from '../components/HelloWorldWidget';

// Simple example of a React "smart" component
export default class HelloWorld extends React.Component {
static propTypes = {
name: PropTypes.string.isRequired, // this is passed from the Rails view
};
..
}



WebpackでバンドルしたJSを使うための変更


config/initializers/react_on_rails.rb

ReactOnRails.configure do |config|

config.generated_assets_dir = File.join(%w(app assets webpack))
config.webpack_generated_files = %w( webpack-bundle.js )
config.server_bundle_js_file = "webpack-bundle.js"
config.npm_build_test_command = "npm run build:test"
config.npm_build_production_command = "npm run build:production"
config.prerender = false
config.trace = Rails.env.development?
config.development_mode = Rails.env.development?
config.replay_console = true
config.logging_on_server = true
config.raise_on_prerender_error = false # change to true to raise exception on server if the JS code throws
config.server_renderer_pool_size = 1 # increase if you're on JRuby
config.server_renderer_timeout = 20 # seconds
config.skip_display_none = false
config.server_render_method = "ExecJS"
config.symlink_non_digested_assets_regex = /\.(png|jpg|jpeg|gif|tiff|woff|ttf|eot|svg|map)/
end


config/initializers/assets.rb

+Rails.application.config.assets.paths << Rails.root.join("app", "assets", "webpack")



app/assets/javascripts/application.js

+//= require webpack-bundle



Railsアプリケーションの変更


config/routes.rb

+  get 'hello_world', to: 'hello_world#index'



app/controllers/hello_world_controller.rb

class HelloWorldController < ApplicationController

def index
@hello_world_props = { name: "Stranger" }
end
end


app/views/hello_world/index.html.erb

<h1 class="alert alert-info this-works">Hello World</h1>

<%= react_component("HelloWorldApp", props: @hello_world_props, prerender: false) %>


起動

さらに必要なライブラリをインストールする。

$ bundle && npm i

起動

$ npm run rails-server

> react-webpack-rails-tutorial@0.0.1 rails-server /Users/satzz/APP_NAME
> echo 'visit http://localhost:3000/hello_world' && foreman start -f Procfile.dev

visit http://localhost:3000/hello_world
..

シーケンスは次の通り。



  1. package.jsonからforemanを起動


    • foremanはProcfileベースでアプリケーション管理するRuby製ツール


      • JSのコードベースの変更を監視して文法エラーなどの警告も行う





  2. foremanがProcfile.devを読みRailsサーバーを起動、同時にclient/package.jsonをたどってwebpackを起動

  3. webpackが、webpack.config.jsに書かれたHelloWorldApp.jsxをエントリポイントにJSをバンドルし、
    ./app/assets/webpack/webpack-bundle.jsを生成


    • 生成されたファイルは.gitignoreされている



  4. Railsが、生成されたwebpack-bundle.jsを使う


    • Railsとのインターフェースに使われる(=react_componentで呼ばれる)全てのReactコンポーネントが、ReactOnRails.registerを使って一意な名前で公開されている必要がある




動作確認

http://localhost:3000/hello_world

で動作確認する。

Screen Shot 2016-11-01 at 11.13.56.png


Herokuで動かす

$ git add .

$ git commit -m'make react work'

$ heroku create

Buildpackの順番調整

$ heroku buildpacks:clear --app dark-wizard-97318

$ heroku buildpacks:add heroku/nodejs --app dark-wizard-97318
$ heroku buildpacks:add heroku/ruby --app dark-wizard-97318

デプロイ

$ git push https://git.heroku.com/dark-wizard-97318.git master