RailsなプロジェクトでReact.jsを利用する1つの例

2016年当時それなりに苦労してRails4.xにReact.jsを導入しましたが、記録に残し忘れていたので、今さらながらブログに書いてみようかと思います。

構成

React.jsを導入するだけならGemからインストールするのが楽なのですが、後日様々なNodeパッケージを導入する可能性を考えて、全てpackage.jsonで管理することにしました。 一方でアセットの配信は既存の仕組みに乗っかりたかったので、assetの配信はSprocketsにお任せすることに。

Node

Rubyはrbenvでインストールしていたので、Nodeもndenvを使うことにしました。

Webpack + Babel

ReactのコンポーネントはES6で書きたくなるので、Webpack + Babelでトランスパイルしています。

react-rails

react_component というViewHelperが便利なので、これを使うためだけにインストールしています。

ディレクト

app/frontend を新たに作成し、ここにReactコンポーネントのソースを格納しています。

├── app
│   ├── assets
│   │   ├── images
│   │   ├── javascripts
│   │   └── stylesheets
│   ├── frontend
│   │   ├── src
│   │   └── test
├── config
│   └── webpack
│       ├── development.js
│       └── production.js
├── package.json

設定

主な設定を書いておきます。2年前なので若干古いかもしれません。。

.babelrc

{
  "presets": ["env", "react"],
  "env": {
    "development": {
      "plugins": [
        "react-hot-loader/babel"
      ]
    }
  }
}

package.json

{
  "version": "1.0.0",
  "scripts": {
    "start": "webpack --config config/webpack/development.js --hot",
    "release": "webpack --config config/webpack/production.js",
    "test": "npm run mocha",
    "bundle-size-analyzer": "webpack --config config/webpack/production.js --json | webpack-bundle-size-analyzer",
    "mocha": "NODE_ENV=test mocha --compilers js:babel-register --require app/frontend/test/setup.js app/frontend/test/**/*.spec.js"
  }
}

config/webpack/development.js

const webpack = require('webpack');

module.exports = {
  entry: [
    './app/frontend/src/components.js'
  ],
  output: {
    path: './app/assets/javascripts/build',
    filename: 'components.js'
  },
  watch: true,
  module: {
    loaders: [{
      test: /\.jsx?$/,
      exclude: /node_modules/,
      loaders: ["babel-loader"]
    }]
  },
  resolve: {
    extensions: ['', '.js', '.jsx']
  }
}

開発

開発に必要な準備は(nodeのインストールを除けば) npm install && npm start するだけです。

エントリーポイントになっている component.js でrequireしておき、

// app/frontend/src/components.js
window.React = require('react');
window.ReactDOM = require('react-dom');
window.PropTypes = require('prop-types');
window.MyApp = Object.assign(
  {
    MyAwesomeComponent: require('./components/MyAwesomeComponent').default
  }
);

Railsのviewでreact_componentを呼び出します。

react_component('MyApp.MyAwesomeComponent', {})

デプロイ

capistranoに下記タスクを追加することで、deploy:compile_assets の前に webpack --config config/webpack/production.js が走ります。

# lib/capistrano/tasks/webpack.rake
namespace :webpack do
  desc "Release build"
  task :build_release do
    on roles(fetch(:ndenv_roles, :all)) do
      within release_path do
        execute :npm, 'run', 'release'
      end
    end
  end

  before 'deploy:compile_assets', 'webpack:build_release'
end

結果、app/assets/jabascripts/build/components.js にファイルが出力されるので、あとはアセットパイプラインのお仕事です。

まとめ

書き殴りになってしまいましたが、RailsなプロジェクトでReact.jsを利用している事例を書いてみました。 2018年に何をいまさら感はありますが、自分の備忘録として。