LoginSignup
77
64

More than 5 years have passed since last update.

Rails5+webpacker+Reactを試してみた

Last updated at Posted at 2017-01-14

webpacker
https://github.com/rails/webpacker

確認バージョン

  • Ruby 2.3.3
  • Rails 5.0.1
  • webpacker 確認時点でのhash:215cdbc5858309de85d71932aa3468bb76feb4a2

Railsアプリ作成

適当に新規Railsアプリを作る

$ mkdir webpack-sandbox
$ cd webpack-sandbox
$ rails new -T .

Gemfileを変更(追加)
(GitHub指定が無いと rake webpacker:install:react が使えない)

gem 'webpacker', github: 'rails/webpacker'

インストール & 確認

$ bundle install
$ bundle exec webpack -h
webpack 1.14.0
Usage: https://webpack.github.io/docs/cli.html

Options:
  --help, -h, -?
  --config
  --context
  ...

テンプレートを生成する

$ bundle exec bin/rails webpacker:install
      create  app/javascript
      create  app/javascript/packs/application.js
       exist  bin
      create  bin/webpack-dev-server
      create  bin/webpack-watcher
      create  bin/webpack
      create  bin/yarn
      create  config/webpack
      create  config/webpack/development.js
      create  config/webpack/production.js
      create  config/webpack/shared.js
      append  .gitignore
         run  ./bin/yarn add --dev webpack@beta webpack-merge webpack-dev-server@beta path-complete-extname babel-loader babel-core babel-preset-latest coffee-loader coffee-script rails-erb-loader from "."
yarn add v0.17.10
info No lockfile found.

...

生成後の構成(特徴的なもののみ抜粋)

.
├── Gemfile
├── Gemfile.lock
├── README.md
├── Rakefile
├── app
│   └── javascript
│       └── packs
│           └── application.js
├── bin
│   ├── webpack
│   ├── webpack-dev-server
│   ├── webpack-watcher
│   └── yarn
├── config
│   └── webpack
│       ├── development.js
│       ├── production.js
│       └── shared.js
└── vendor
    ├── assets
    │   └── javascripts
    ├── package.json
    └── yarn.lock
  • package.jsonはvendor配下に配備される
  • shared.js → development.js / production.js 両方から参照される

ビルドする

$ bundle exec bin/webpack
Hash: 071bb7221801f498ad46
Version: webpack 2.2.0-rc.4
Time: 482ms
             Asset     Size  Chunks             Chunk Names
    application.js  3.37 kB       0  [emitted]  application
application.js.map  3.34 kB       0  [emitted]  application
   [0] ../app/javascript/packs/application.js 496 bytes {0} [built]

Viewから読み込む

jsの読み込みを変更

application.html.erb
<%= javascript_pack_tag 'application' %>

起動してみる

適当にコントローラを作成

$ bundle exec rails g controller Sample index
routes.rb
root to: 'sample#index'

起動

$ bundle exec rails s

上手くいけばコンソールにログが出力される

Kobito.sRykAI.png

ダイジェスト値の付与を確認(production起動)

ただこの場合、development環境のため、jsにダイジェスト値が付与されていない。
productionでダイジェストが付与されることを確認してみる。

SERCRET_KEY_BASEを設定

$ bundle exec rake secret

出力されたhash値を設定

$ export SECRET_KEY_BASE={hash}

digestファイルを生成

$ bundle exec rake webpacker:compile

production用ビルド & 起動

$ RAILS_ENV=production bundle exec bin/webpack
$ export RAILS_SERVE_STATIC_FILES=true
$ RAILS_ENV=production bundle exec rails s

Kobito.aY8GUA.png

ダイジェストが付与されているスクリプトがロードされてますね。

Reactを使う

$ bundle exec bin/rails webpacker:install:react
application.html.erb
<%= javascript_pack_tag 'hello_react' %>
$ bundle exec bin/webpack
$ bundle exec rails s

Kobito.b7Y3B9.png

デフォルトで生成されるhello_react.jsのHelloコンポーネントが出力されている。

コンポーネントを追加してみる

適当にコントローラを追加

$ bundle exec rails g controller Count index

衝突しないようにデフォルトのスクリプトを外す

application.html.erb
<head>
  <title>WebpackerSandbox</title>
  <%= csrf_meta_tags %>
</head>

スクリプト作成

import/exportの挙動確認の意味も込めて無意味にネスト

.
├── counter
│   ├── counter.js
│   └── index.js
└── counter.js
/app/javascript/packs/counter.js
import React from 'react'
import ReactDOM from 'react-dom'
import * as counter from './counter/index'

document.addEventListener("DOMContentLoaded", e => {
  ReactDOM.render(<counter.Counter />, document.body.appendChild(document.createElement('div')))
})
/app/javascript/packs/counter/index.js
export * from './counter'
/app/javascript/packs/counter/counter.js
import React from 'react'

export class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: props.count || 0
    }
  }

  handleClick() {
    this.setState({
      count: this.state.count + 1
    })
  }

  render() {
    return (
      <div>
        <div>COUNT: {this.state.count}</div>
        <div><input type="button" value="COUNT UP" onClick={() => this.handleClick()} /></div>
      </div>
    )
  }
}

ビルドして動作確認

スクリプトのロードを末尾に追加

/app/views/count/index.html.erb
<%= javascript_pack_tag 'counter' %>

webpackビルドや起動方法などは先ほどと同じ。

caps.gif

なんか動いてるっぽい。

所感

今までwebpack絡めた環境作るのが手間に感じていたのが、webpacker使うとかなり楽に感じました。

いままではwebpackでビルド→ビルド生成物をasset pipelineに乗せてダイジェスト付与の恩恵だけ受ける、みたいなことをやってたんですが、そのあたりも含めて面倒見てくれるのは嬉しく思いました。

Rails 5.1に期待。

77
64
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
77
64