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

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

[React.js Tutorial](http://facebook.github.io/react/docs/tutorial.html)ではフロントエンドでの実例が用いられていた。

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

https://github.com/mhart/react-server-example

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

以下記録。

# まずreact-server-exampleを試す

https://github.com/mhart/react-server-example

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

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

```
> git clone git@github.com: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/
```

![Screen Shot 2014-11-15 at 19.41.04.png](https://qiita-image-store.s3.amazonaws.com/0/3985/a61aee2f-5f73-65d4-f6d7-8a0c1cb49e45.png)


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

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

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

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

![Screen Shot 2014-11-26 at 01.56.30.png](https://qiita-image-store.s3.amazonaws.com/0/3985/abef8f59-992d-0eb3-09b8-ff3dae074050.png)

[react-bootstrap](http://react-bootstrap.github.io/)というものを[react components](http://react-components.com/)で見つけたので、
[react-server-example](https://github.com/mhart/react-server-example)のコードを元にreact-bootstrapを使うサンプルを書いてみた。

## サンプルのリポジトリ

**[react-server-bootstrap-example](https://github.com/futoase/react-server-bootstrap-example)**

## サンプルの動かし方

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

```
> git clone git@github.com:futoase/react-server-bootstrap-example.git
> cd react-server-bootstrap-example
> npm install
> node server.js
```

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

```
> open http://localhost:3000
```

![Screen Shot 2014-11-26 at 00.32.10.png](https://qiita-image-store.s3.amazonaws.com/0/3985/7c3ff709-0b8e-3dfe-8720-c8cdd725dee3.png)

# 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](http://gruntjs.com/)

![Screen Shot 2014-11-26 at 01.44.51.png](https://qiita-image-store.s3.amazonaws.com/0/3985/1b833832-d7e3-bc51-2f60-35543a032505.png)

[grunt-react](https://github.com/ericclemmons/grunt-react)を使うために利用した。

```
> grunt
```

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

- ソースファイルの結合

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

### [ECT](http://ectjs.com/)

![Screen Shot 2014-11-26 at 01.47.03.png](https://qiita-image-store.s3.amazonaws.com/0/3985/d041b253-92c3-472f-fdcb-a63932789443.png)

爆速テンプレートエンジンという。サーバサイド側がレンダリングするフロントエンド側の
テンプレートを出力するために使った。もともと[参考にしていたreact-server-exampleでは
文字列結合をしていたため。](https://github.com/mhart/react-server-example/blob/479df878a4679c2c2814f21d64a842fda7e4b85e/server.js#L37)

[テンプレートファイルはこちら](https://github.com/futoase/react-server-bootstrap-example/tree/master/templates)

### [browserify](http://browserify.org/)

![browserify-img](https://camo.githubusercontent.com/e19e230a9371a44a2eeb484b83ff4fcf8c824cf7/687474703a2f2f737562737461636b2e6e65742f696d616765732f62726f777365726966795f6c6f676f2e706e67)

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

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

### [literalify](https://github.com/pluma/literalify)

[browserify-transform-tools](https://github.com/benbria/browserify-transform-tools)を利用したもののようだ。

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

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

```js: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)
      )
    );
  }
});
```

```js: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](https://fb.me/react-0.12.0.min.js)により、定義されている。

```js: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](https://github.com/substack/node-browserify/wiki/list-of-transforms)に書かれているプロダクトリポジトリを見て回って面白かった。

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

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

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

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