私のReact用SPA向けgulpfile.js

# 動機
ReactでSPAを作ろうとしたとき、何も工夫せずにbrowserifyを使うとコンパイル等で非常に時間がかかったり、生成物のサイズがでかくなりすぎたりしがちです。
そこで、ライブラリ等はなるべくCDN経由で取得してみてはどうかと思い、gulpfile.jsを考えてみました。
結果として、コンパイル後の生成物のサイズが抑えられ、タスクも短時間で完了するようになりました。（たとえばuglifyを使う場合などには如実です）

# npmパッケージ
まず、本記事で利用するnpmパッケージは、次のとおりです。
（バージョン等は、投稿時のものです。）

```json:package.json
{
  ... 省略 ...
  "dependencies": {
    "babel-preset-es2015": "^6.3.13",
    "babel-preset-react": "^6.3.13",
    "babelify": "^7.2.0",
    "browserify": "^12.0.1",
    "gulp": "^3.9.0",
    "literalify": "^0.4.0",
    "react": "^0.14.3",
    "react-dom": "^0.14.3",
    "react-router": "^1.0.0"
  }
}
```

# gulpfile.js
gulpfile.jsは下記のようにしてみました。
内容としては、browser.jsxをbrowser.jsにコンパイルするというものです。babelifyの後にliteralifyを使っているのがポイントです。

```js:gulpfile.js
const gulp = require('gulp');
const browserify = require('browserify');
const babelify = require('babelify');
const literalify = require('literalify');
const fs = require('fs');

gulp.task('browser', () => {
  return browserify({debug: true})
  .transform(babelify.configure({
    presets: ['es2015', 'react']
  }))
  .transform(literalify.configure({
    'react': 'window.React',
    'react-dom': 'window.ReactDOM',
    'react-router': 'window.ReactRouter'
  }))
  .require('browser.jsx', {entry: true})
  .bundle()
  .on('error', (error) => {
    console.log(`Error: ${error.message}`);
  })
  .pipe(fs.createWriteStream('browser.js'));
});
```

# index.html
次に、SPAのレンダリング先となるindex.htmlを準備します。reactやreact-router等はcdnjsから取ってくるようにしています。

```html:index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="x-ua-compatible" content="ie=edge" />
    <title>SPA</title>
  </head>
  <body>
    <div id="application"></div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.3/react.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.3/react-dom.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-router/1.0.0/ReactRouter.js"></script>
    <script src="browser.js"></script>
  </body>
</html>
```

# JSXファイル
説明用のシンプル（すぎる）アプリケーションは次のとおりです。特筆すべき点はありません。ご参考まで。

```js:browser.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import {Router, Route} from 'react-router';

const Header = () => (
  <header>header</header>
);

const Main = () => (
  <main>main</main>
);

const Footer = () => (
  <footer>footer</footer>
);

const Application = React.createClass({
  render() {
    return (
      <div>
        <Header />
        <Main />
        <Footer />
      </div>
    );
  }
});

ReactDOM.render((
  <Router>
    <Route path="/" component={Application} />
  </Router>
), document.getElementById('application'));
```

# $ gulp browser [Enter]
これで、ひとまずコマンドラインでの`gulp browser`が実行できるようになります。
（その前に`npm install -g gulp`も必要かも）

できあがったjsファイルを覗いてみると、うまいこと動いていることが確認できます。

```js
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){... 省略 ...
'use strict';

var _react = window.React;

var _react2 = _interopRequireDefault(_react);

var _reactDom = window.ReactDOM;

var _reactDom2 = _interopRequireDefault(_reactDom);

var _reactRouter = window.ReactRouter;

... 省略 ...
```


# おわりに
名前の付け方やディレクトリ分け等については、社内文化などもあると思いますので適宜設定ください。その際は、fs.createWriteStreamのパス指定先のディレクトリがない場合にエラーがでますので、予め出力先ディレクトリを準備する必要があります。
そのほか、必要あらばgulpのwatchタスク等もご準備ください。

あと気になった点としては、requireとimportの使い分けが必要なところが、一貫性という点では問題のある方法かもしれません...