【個人メモ】React.jsを使ってserver-sideレンダリングを試す


React.jsのserver-side レンダリングを試す

React.js Tutorialではフロントエンドでの実例が用いられていた。

githubリポジトリ上には、React.jsを使ってDOM(Virtual DOM)をサーバサイド側で構築し、
フロントエンド側にはレンダリング結果を返す、というサンプルがある。

このサンプルを試用して
react-bootstrapを使ったりGrunt 使ったりして
自分なりにReact.jsでのserver-sideレンダリングに対する理解を深めるため
コードを書いてみよっかなと思った。

以下記録。

まずreact-server-exampleを試す

git cloneし、動作確認をしてみた。

プロジェクトソースを手元に持ってくる

> git clone [email protected]:mhart/react-server-example.git

必要なパッケージのインストール

> cd react-server-example
> npm install

react-server-exampleを起動してみる

react-server-exampleのディレクトリ以下で、
server.jsを起動する

> node server.js
Listening on 3000…

ブラウザでアクセスしてみる

> open http://localhost:3000/

おお、レンダリングされてる。

var props = {items: [0, 1, '</script>', '<!--inject!-->’]}

の内容がレンダリングされている。なるほど。

react-bootstrapを使ったサンプルを書いてみる

react-bootstrapというものをreact componentsで見つけたので、
react-server-exampleのコードを元にreact-bootstrapを使うサンプルを書いてみた。

サンプルのリポジトリ

react-server-bootstrap-example

サンプルの動かし方

githubリポジトリをcloneし、npm installし、
node server.jsで立ち上げる

> git clone [email protected]:futoase/react-server-bootstrap-example.git
> cd react-server-bootstrap-example
> npm install
> node server.js

サーバが立ち上がった後、http://localhost:3000をブラウザで開く

> open http://localhost:3000

react-server-bootstrap-exampleをどう構成しているか

ディレクトリツリー

こんな感じ。

.
├── Gruntfile.js
├── LICENSE-MIT
├── README.md
├── dest
│   └── app.js
├── npm-debug.log
├── package.json
├── server.js
├── src
│   ├── jumbotron.js
│   ├── main.js
│   ├── page.js
│   └── tab.js
└── templates
    ├── index.ect
    └── layout.ect

React.js以外で使ったもの

grunt

grunt-reactを使うために利用した。

> grunt

このコマンド一発で、複数のJSXファイルが一つのjsファイル(src/app.js)にまとめられる。
ファイルの変更を見てるだけだけど。(単体ファイルならreact-toolsでもできる)

  • ソースファイルの結合

JSXファイルを[srcディレクトリ以下[(https://github.com/futoase/react-server-bootstrap-example/tree/master/src)に書いているのだけど、
jsxコマンド(react-tools)で作るのではなく、grunt使ってdest/*.jsをsrc/app.jsに結合するようにした。

ECT

爆速テンプレートエンジンという。サーバサイド側がレンダリングするフロントエンド側の
テンプレートを出力するために使った。もともと参考にしていたreact-server-exampleでは
文字列結合をしていたため。

テンプレートファイルはこちら

browserify

参考にしていたreact-server-exampleから。
browserifyについてあんましっかりとした認識はなかったが、
サーバサイドでレンダリングしたJSに対しrequire文を使って
node.js側で生成したjsのモジュールをフロントエンド側に渡せるんだなというのが良い。

/dest/bundle.jsにアクセスすると、
/dest/app.jsとしてJSXから変換されたjsファイルを取り込んだ形で
フロントエンド側に提供することができる。よく出来てるなあ...

literalify

browserify-transform-toolsを利用したもののようだ。

literalifyそのものは、src/app.jsrequire('react')window.Reactに置き換える。

以下に比較できるソースコードを貼る。

app.jsの一部
var React = require('react');

module.exports = React.createClass({displayName: 'exports',
  render: function() {
    return (
      React.createElement("div", {className: "container"}, 
        React.createElement(JumbotronBox, null), 
        React.createElement(TabbedAreaBox, null), 
        React.createElement(PageHeaderTitle, null), 
        React.createElement(PageMessage, null)
      )
    );
  }
});
bundle.jsの一部
var React = window.React;

module.exports = React.createClass({displayName: 'exports',
  render: function() {
    return (
      React.createElement("div", {className: "container"}, 
        React.createElement(JumbotronBox, null), 
        React.createElement(TabbedAreaBox, null), 
        React.createElement(PageHeaderTitle, null), 
        React.createElement(PageMessage, null)
      )
    );
  }
});

window.Reactはどっから来るんだろっていうのは、facebookのReact.js用のCDNにより、定義されている。

React.js0.12.0(CDN)
var t;"undefined"!=typeof window?t=window:"undefined"!=typeof global?t=global:"undefined"!=typeof self&&(t=self),t.React=e()}}(function(){return function e(t,n,r){function o(i,s){if(!n[i]){if(!t[i]){var u="function"==typeof require&&require;if(!s&&u)return u(i,!0);if(a)return a(i,!0);var c=new Error("Cannot find module '"+i+"'");

"undefined"!=typeof window?t=windowによって、window.React(t.React)が定義されている。

話がずれるけど

browserifyすごいなぁ。サーバサイドレンダリング側とフロントエンド側の
オブジェクトを糊でくっつける感じだ。

list-of-transformsに書かれているプロダクトリポジトリを見て回って面白かった。

React.jsのserver-sideレンダリングを試してみて

React.jsのserver-sideレンダリングを試して、
面白いなと思った。

また、browserifyについて触ってなかったので
どういったものなのかが知見が得られた。面白いなあ。

こういうのがどんどん出てくるので楽しい。