WebpackでReactをビルドしたものをRailsでサーバサイドレンダリングする方法をまとめました。
Webpack側
$ npm i -D webpack babel babel-loader babel-core
$ npm i -D babel-preset-react babel-preset-es2015
Reactのコンポーネントのテストを書く場合はreact
とreact-dom
をインストールする必要があります。
そうでない場合はインストールしなくても、react-railsにこれらが含まれているので問題ありません。
Webpackの設定
Reactのコンポーネントをreact
ディレクトリに配置して、ビルドしたものはapp/assets/javascripts/components
に出力されるようにします。
react
とreact-dom
はreact-railsのものを利用するので、externalsに設定しておきます。
const DEBUG = !process.argv.includes('--release');
module.exports = {
cache: DEBUG,
debug: DEBUG,
entry: {
Hoge: './react/Hoge.jsx',
},
output: { path: './app/assets/javascripts/components', filename: '[name].js' },
devtool: DEBUG ? 'inline-source-map' : false,
module: {
loaders: [
{
test: /.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/,
query: {
presets: ['es2015', 'react']
}
}
]
},
resolve: {
extensions: ['', '.js', '.jsx'],
},
externals: {
'react': 'React',
'react-dom': 'ReactDOM'
},
}
Reactのコンポーネント
Reactのコンポーネントは以下のように、サーバサイドレンダリングするオブジェクトをwindowのプロパティとして出力します。
import React from 'react';
class Hoge extends React.Component {
render() {
return (
<div>
hogehoge
</div>
)
}
}
window.Hoge = Hoge;
package.json
package.jsonにはscriptを設定します。
開発する時はnpm run build
やnpm run watch
コマンドを使うといいと思います。
{
"scripts": {
"build": "webpack",
"watch": "webpack --watch",
"release": "webpack --release"
},
}
Rails側
react-railsをインストール
gem 'react-rails'
$ bundle install
$ bundle exec rails g react:install
config.react.variant
を設定
Rails.application.configure do
+ config.react.variant = :development
end
Rails.application.configure do
+ config.react.variant = :production
end
production環境の設定
server_rendering.jsを新たに作成します。
//= require react-server
//= require components
それぞれのファイルに追記します。
Rails.application.config.assets.precompile += %w( server_rendering.js )
Rails.application.configure do
config.react.variant = :production
+ config.react.server_renderer_options = {
+ files: ["server_rendering.js"],
+ }
end
Precompile時にWebpackでビルドするために、以下のファイルを新たに作成します。
task :build_react do
sh "npm run release"
end
Rake::Task["assets:precompile"].enhance(%i(build_react))
Reactのコンポーネントのレンダリング
react_componentに表示したいコンポーネントと、引数を渡します。
題3引数に{prerender: true}
を渡してサーバサイドレンダリングを有効にしています。
<%= react_component('Hoge', {}, {prerender: true}) %>
おわりに
今回編集および追加したファイルは以下のようになっています。
rails_root
├── app/
│ └── assets
│ └── javascripts
│ ├── application.js
│ ├── components
│ ├── components.js
│ └── server_rendering.js
├── config/
│ ├── environments
│ │ ├── development.rb
│ │ └── production.rb
│ └── initializers
│ └── assets.rb
├── lib/
│ └── tasks
│ └── before_precompile.rake
├── react/
│ └── Hoge.jsx
├── Gemfile
├── package.json
└── webpack.config.js
app/assets/javascripts/components
はビルドするたびに変更が発生するので、gitを使って複数人で開発しているとコンフリクトしやすいです。
gitignoreにapp/assets/javascripts/components
以下のファイルを無視するように設定しておくべきかもしれません。