RailsでReactを動かしてみる (browserify + watchify + reactify)


[react.js](http://facebook.github.io/react/)をRails4.2.1で動かしてみたのでメモ。
今回作成したソースコードは[ysm001/rails-react-sample](https://github.com/ysm001/rails-react-sample)に置いてあります。

## 使い方
```
npm install
bundle install
npm start
```

## railsプロジェクトの作成
```
$ rails new rails_react
$ cd rails_react
```

## package.json
npm initとかでpackage.json生成。

```package.json
{
  "name": "rails-react",
  "license": "MIT",
  "engines": {
    "node": ">= 0.10"
  }
}
```

## 必要なmoduleのinstall
以下のコマンドを実行して必要なmoduleをinstallする。

```
npm install --save-dev browserify reactify watchify
npm install --save react react-router react-tap-event-plugin
```
browserify: クライアントでもrequireを使ってnode moduleの読み込みが可能にするmodule
reactify: jsxをjsに変換するmodule
watchify: ファイルの変更を検知してbrowserifyしなおしてくれるmodule 

reactみたいなでっかいファイルを毎回browserifyするとめちゃくちゃ重いので、watchify使って差分だけbrowserifyする。


## npm scripts
以下のscriptをpackage.jsonに追記。

```package.json
  "scripts": {
    "bundle": "browserify -t reactify app/assets/javascripts/app.jsx > app/assets/javascripts/bundle.js",
    "watch-js": "watchify -t reactify app/assets/javascripts/app.jsx -o app/assets/javascripts/bundle.js -v",
    "start": "npm run watch-js & rails s"
  }
```

bundle: app.jsxをbrowserifyしてbundle.jsに吐く
watch-js: app.jsを監視して、変更点をbundle.jsに適用
start: ファイル監視 & railsサーバ起動

## application.jsの変更
依存関係にあるファイルはrequireで読み込んでいくので、``` application.js ```に書いてある``` require_tree . ``` は不要。

なので、``` app/assets/javascripts/application.js ```から
``` //= require_tree . ```
を削除して
```//= require bundle.js ```
を追加。

## 表示するページの作成
テスト用に適当にページを作ります。
``` app/assets/javascripts/app.jsx ``` にアプリケーションのメインとなる処理を記述。
とりあえず、以下のような感じでRouterを使った処理を書いてみました。

``` app/assets/javascripts/app.jsx 
(function() {
  var React = require('react');
  window.React = React; // Reactオブジェクトだけは外に出しておく

  var injectTapEventPlugin = require("react-tap-event-plugin");
  injectTapEventPlugin();

  var Router = require('react-router');
  var AppRoutes = require('./app-routes.jsx');

  $(function() {
    Router.run(AppRoutes, function (Handler) {
      React.render(<Handler/>, document.body);
    });
  });
}) ();
```


Routerも適当になんか書いておく。

```app/assets/javascripts/app-routes.jsx 
var React = require('react');
var Router = require('react-router');
var DefaultRoute = Router.DefaultRoute;
var Route = Router.Route;
var RouteHandler = Router.RouteHandler;

var Root = React.createClass({
  render: function() {
    return (
        <div>
          <p>header</p>
          <RouteHandler/>
          <p>footer</p>
        </div>
    );
  }
});

var PathA = React.createClass({
  render: function() { return <p>path A</p>; }
});

var PathB = React.createClass({
  render: function() { return <p>path B</p>; }
});


var AppRoutes = (
  <Route name="app" path="/" handler={Root}>
    <DefaultRoute handler={PathA}/>
    <Route name="path-a" path="/path-a" handler={PathA} />
    <Route name="path-b" path="/path-b" handler={PathB} />
  </Route>
);

module.exports = AppRoutes;
```

表示用にコントローラを用意。react#indexで何か表示してみることにします。

```
bundle exec rails g controller react index
```

## 実行
```
npm start
```
した後、``` http://localhost:3000/react/index ```にアクセスすると

```
header
path a
footer
```
と表示されているかと思います。
``` http://localhost:3000/react/index#/path-b ```にアクセスするとpath aがpath bに書き変わり、正常に動作していることが確認できます。

また、``` app.jsx ```や``` app-routes.jsx ```を編集すると、ファイルの更新が自動で``` bundle.js ```に反映されて、リロードした際に変更点が反映されているのが確認できるかと思います。

# 参考文献
* [Using Browserify with Ruby on Rails](http://learnjs.io/blog/2014/03/17/using-browserify-with-rails/)