ReactでTodo appを作るまで(開発環境編)

Reactを使おうとすると、ファイルの変換やらなんやら色々あるので、まずは簡単なsampleを使って各種開発環境を整えてみる。

#前提
npmを利用
ブラウザはchrome
最終的につくるのはこれ（http://todomvc.com/examples/react/#/）

#目次
1. sampleページの作成
2. webサーバの導入
3. サーバーサイドでの変換
4. browserifyの導入
5. ファイル変更の監視とgulpジョブ
6. sassの導入

までを行う。
続きは[実装編](http://qiita.com/haradakunihiko/items/80e3eab0916afa54e4a7)へ

## 簡単なsampleページ
単体で動作する簡単なsample。

```html:index.html
<html>
<head>
    <script src="http://fb.me/react-with-addons-0.12.2.js"></script>
    <script src="http://fb.me/JSXTransformer-0.12.2.js"></script>
</head>
<body>
<div id="todo-app"></div>
<script type="text/jsx">
    React.render(
            <h1>Sample</h1>,
            document.getElementById('todo-app')
    );
</script>
</body>
</html>
```

## scriptを切り出す
htmlにscriptを全て書いていくわけには行かないので、まずはsrc/app.jsへ切り出す

*JSXTransformerがajax通信を行う。chromeだとXHRでfile://へのアクセスができない(same origin policy)のでこのままだとエラーが発生する

## webサーバーの導入
webサーバーを起動してアクセスする。

```console
npm instal http-server -save
$(npm bin)/http-server
```

## npm scriptを利用してwebサーバーの起動を簡単に
package.jsonにスクリプトを記述して起動する

```diff:package.json
   "scripts": {
+    "start": "http-server",
     "test": "echo \"Error: no test specified\" && exit 1"
   },
```
```console
npm start
```

## jsxのサーバーサイドでの変換
jsxを毎回クライアントサイドで変換するのは当然速度的にNG。サーバーサイドでjsxをjavascriptに変換する。
(ただし、実際にはbrowserifyの導入後、以下のjsxコマンドは不要になる)

react-toolsの導入

```console
npm install react-tools -save-dev
```

jsxコマンドの実行で、jsx => javascriptへ変換

```console
$(npm bin)/jsx --harmony src/ build/
```

watchさせる場合は、

```console
$(npm bin)/jsx --harmony --watch src/ build/
```

合わせてhtmlを修正。text/jsxではなくtext/javascriptになる

```diff:index.html
  <html>
  <head>
     <script src="http://fb.me/react-with-addons-0.12.2.js"></script>
-    <script src="http://fb.me/JSXTransformer-0.12.2.js"></script>
  </head>
  <body>
  <div id="todo-app"></div>
- <script type="text/jsx" src="src/app.js">
+ <script type="text/javascript" src="build/app.js">
  </script>
  </body>
  </html>
```

## browserifyの導入
reactJsでは、pluginの導入を含めてcommonJS形式で依存性の解決をすると便利なようのようなので、browserifyを導入する。
browserifyは基本的にjavascriptファイルの変換を行う。jsx記法はそのままでは変換できないため、ここではまずjsxコマンドで変換したjavascriptファイルをターゲットとして依存性の解決のみ行う。

### 別のスクリプトファイルを作成し、app.jsで利用する

依存性解決のサンプルとして、新しいスクリプトファイルを作成してapp.jsで読み込む実装をしてみる。

```js:src/util.js
var util = function(){
    console.log('util');
}
module.exports = util;
```
```js:src/app.js
var util = require('./util.js')

React.render(
    <h1>TODO</h1>,
    document.getElementById('todo-app')
);

util();
```

browserifyのinstall

```console
npm install browserify -save-dev
```

build/app.jsをbrowerifyで変換

```console
$(npm bin)/browserify build/app.js -o build/bundle.js
```

```diff:index.html
  <div id="todo-app"></div>
- <script type="text/javascript" src="build/app.js">
+ <script type="text/javascript" src="build/bundle.js">
  </script>
  </body>
```

ここまででは、
1. jsxコマンドでsrc/app.js => build/app.js
2. browserifyコマンドでbuild/app.js => build/bundle.js

の二つの変換を行った。

### reactifyの導入
reactifyは、browserifyのtransform module。jsxファイルをjavascriptへ変換してくれる。これによって、JSX => javascript(commonJS) => javascriptという変換が行われる。

reactifyの導入

```console
npm install reactify -save-dev
```
src/app.jsを指定して直接変換

```console
$(npm bin)/browserify -t reactify src/app.js -o build/bundle.js
```

htmlは以下のまま変更無し

```html
<html>
<head>
    <script src="http://fb.me/react-with-addons-0.12.2.js"></script>
</head>
<body>
    <div id="todo-app"></div>
    <script type="text/javascript" src="build/bundle.js">
    </script>
</body>
</html>
```

### react.jsをbrowserifyで解決する。

htmlに直接書いたreact-with-addons-0.12.2.jsをcommonJS形式で記述し、browserifyで依存性を解決する

```diff:index.html
 <head>
-     <script src="http://fb.me/react-with-addons-0.12.2.js"></script>
 </head>
```

```diff:src/app.js
+ var React = require('react/addons');
  var util = require('./util.js');
```

reactの導入

```console
npm install react -save
```

browserifyを再実行

```console
$(npm bin)/browserify -t reactify src/app.js -o build/bundle.js
```

### 変更の監視
依存しているファイルの変更を監視するwatchifyを導入する

watchfyの導入

```console
npm install watchify --save-dev
```

watchifyを実行

```console
$(npm bin)/watchify -t reactify src/app.js -o build/bundle.js -v
```

src/util.jsやapp.jsの変更を監視し、自動でファイルの変換が行われる。

## 変更を監視するジョブの作成

```script
npm install gulp --save-dev
npm install vinyl-source-stream --save-dev
npm install gulp-duration --save-dev
npm install gulp-util --save-dev
```

```js:gulpfile.js
var gulp = require('gulp');
var browserify = require('browserify');
var reactify = require('reactify');
var watchify = require('watchify');
var source = require('vinyl-source-stream');
var duration = require('gulp-duration');
var gulpUtil = require('gulp-util');

var buildScript = function(watch){
    var bundler = browserify(['./src/app.js'],{
        cache:{},
        packageCache:{},
        verbose:true,
        debug:true
    });
    if(watch){
        bundler = watchify(bundler);
    }
    bundler.transform(reactify);

    var rebundle = function(){
        gulpUtil.log('start bundle');
        return bundler.bundle()
        .on('error',function(err){
                console.log(err.message);
                this.emit('end');
            })
        .pipe(source('bundle.js'))
        .pipe(duration('rebuilding files'))
        .pipe(gulp.dest('./build/'));
    }

    bundler.on('update',rebundle);
    return rebundle();
}

gulp.task('build:script', function() {
    return buildScript(false);
});
gulp.task('watch:script', function() {
    return buildScript(true);
});

```

```script
gulp build
gulp watch
```
で実行を確認


## sassの導入
最後に、、sassでスタイルを記述するため、sassのbuildと監視タスクを作成する

```script
npm install gulp-sass --save-dev
```

sassの変換と、watchタスクの追加。

```js:gulpfile.js
var sass = require('gulp-sass');

gulp.task('build:sass', function () {
    gulp.src('./src/sass/**/*.scss')
        .pipe(sass().on('error', sass.logError))
        .pipe(gulp.dest('./css'));
});

gulp.task('build',['build:script','build:sass']);

gulp.task('watch',['watch:script','build:sass'],function(){
    gulp.watch( './src/sass/**/*.scss', ['build:sass'] );
});

```

sassの導入に伴い、ファイル構成を少し変更する。

```
index.html
src
 ├js
 │ └app.js
 └sass　　
   └main.scss
```

#ソースコード
今のところこんな感じになってるはず
https://github.com/haradakunihiko/react-todo-tutorial/tree/v0.1

#参考
##browserify
https://github.com/substack/node-browserify#usage
https://github.com/substack/browserify-handbook#node-packaged-manuscript

##watchify
https://github.com/substack/watchify

##gulpfile/build
http://blog.avisi.nl/2014/04/25/how-to-keep-a-fast-build-with-browserify-and-reactjs/
https://github.com/gulpjs/gulp/blob/master/docs/recipes/fast-browserify-builds-with-watchify.md
https://gist.github.com/Sigmus/9253068

##binyl
http://umai-bow.hateblo.jp/entry/2014/10/08/002235