Redux Example の TODO List を TypeScript で作成２

# Redux Example の TODO List を TypeScript で作成２
(2016.05.08 OS X El Capitan‎)

前回、jspm を使って作成した [Redux Example の TODO List を TypeScript で作成](http://qiita.com/NariseT/items/7b5d0e1bc7ba1d21c35b) をもとに、
gulp を使用して、プロジェクトのタスク管理ができるようになることを目的としました。

- [GitHub Pages の TODO List アプリ](http://NariseT.github.io/todo-list2)
- [ソースコード](https://github.com/NariseT/todo-list2)

## 準備

前回と同様に、必要なプログラム、パッケージのインストールをしました。
今回は、jspm の代わりに gulp をインストールしました。

```
brew update
brew install node
npm install typescript -g
npm install typings -g
npm install gulp -g
```

続けて、"todo-list2" という名前のフォルダを作成して、移動し、
`npm init` と入力して、プロジェクトの設定を行いました。
npm init とすると色々と聞かれましたが、すべてデフォルトのままとしました（Enter を連打）。

```
mkdir todo-list2
cd !$
npm init
```

前回は、jspm でインストールしていたパッケージ、react, react-dom, redux, react-redux, es6-shim を、
今回は、npm でインストールした後、
typings を使用してそれらの型定義ファイルをインストールしました。

```
npm i --save-dev react react-dom redux react-redux es6-shim
typings i dt~react --save --global
typings i dt~react-dom --save --global
typings i dt~redux --save --global
typings i dt~react-redux --save --global
typings i dt~es6-shim --save --global
```

続いて、前回の [Redux Example の TODO List を TypeScript で作成](http://qiita.com/NariseT/items/7b5d0e1bc7ba1d21c35b) で作成した 
index.html, tsconfig.json と src/ 以下を、todo-list2/ 直下にコピーしました。

```index.html
<html>
<head>
    <title>Redux Todo Example</title>
</head>
<body>
    <h1>TODO List App</h1>
    <div id="root"></div>
    <script src="build.js"></script>
</body>
</html
```

tsconfig.json に関しては、"module": "system" から、"module": "commonjs" に変更しました
（src/ 以下の import 文でエラーが発生したため、適当に修正をしました）。

```tsconfig.json
{
    "compilerOptions": {
        "target": "es5",
        "sourceMap": true,
        "declaration": true,
        "module": "commonjs",
        "jsx": "react",
        "noImplicitAny": false,
        "noEmitOnError": true,
        "removeComments": true,
        "experimentalDecorators": true
    },
    "compileOnSave": false,
    "filesGlob": [
        "./typings/main.d.ts",
        "./src/*.tsx",
        "./src/**/*.ts",
        "./src/**/*.tsx"
    ],
    "files": [
        "./typings/main.d.ts",
        "./src/index.tsx",
        "./src/actions/index.ts",
        "./src/constants/index.ts",
        "./src/containers/FilterLink.ts",
        "./src/containers/VisibleTodoList.ts",
        "./src/reducers/index.ts",
        "./src/reducers/todos.ts",
        "./src/reducers/visibilityFilter.ts",
        "./src/components/App.tsx",
        "./src/components/Footer.tsx",
        "./src/components/Link.tsx",
        "./src/components/Todo.tsx",
        "./src/components/TodoList.tsx",
        "./src/containers/AddTodo.tsx"
    ],
    "atom": {
        "rewriteTsconfig": true
    }
}
```

## gulp でコンパイルとビルド

- [gulp.jsを使ってフロントエンドのビルドをする【webpack, stylus】](http://yutapon.hatenablog.com/entry/2014/12/06/123000) 
- [Bootstrap for Sass, npm, bower, gulp で快適Web開発環境構築](http://labo.dotsmart.biz/web-bootstrap)

などを参考にさせていただき、gulpfile.js, gulp/, gulp/tasks/ を作成して、以下のようなフォルダ構造を作成しました。

```
tree todo-list2 -L 2 --charset=xyz
todo-list2
|-- gulp
|   `-- tasks
|-- gulpfile.js
|-- index.html
|-- node_modules
|   |-- asap
|   |-- core-js
|   |-- ...
|   |-- ...
|   `-- ...
|-- package.json
|-- src
|   |-- actions
|   |-- components
|   |-- constants
|   |-- containers
|   |-- index.tsx
|   `-- reducers
|-- tsconfig.json
|-- typings
|   |-- browser
|   |-- browser.d.ts
|   |-- main
|   `-- main.d.ts
`-- typings.json
```

npm install で、タスクを管理するのに必要な gulp 関連のパッケージをインストールしました。

```
npm i gulp gulp-typescript gulp-plumber gulp-notify require-dir merge2 run-sequence webpack-stream browser-sync --save-dev
```

とりあえず、gulpfile.js は以下のように作成しました。

```gulpfile.js
require('require-dir')('./gulp/tasks', {recurse: true});
```

gulp/tasks/ に、scripts.js という typescript をコンパイルするタスクを追加しました。

- [gulp-typescript の README](https://github.com/ivogabe/gulp-typescript)
- [gulpタスク実行中にエラーが出たらデスクトップ通知を出す](http://qiita.com/nakajmg/items/8add9c58ea28a8f31eed) 

を参考にさせていただきました。

```scripts.js
var gulp = require('gulp');
var ts = require('gulp-typescript');
var plumber = require('gulp-plumber');
var notify = require('gulp-notify');
var merge = require('merge2');

var tsProject = ts.createProject('tsconfig.json');
gulp.task('scripts', function() {
    var tsResult = tsProject.src()
        .pipe(plumber({errorHandler: notify.onError('<%= error.message %>')}))
        .pipe(ts(tsProject));

    return merge([
        tsResult.js
            .pipe(gulp.dest('dist/js')),
        tsResult.dts
            .pipe(gulp.dest('dist/dts'))
    ]);
});
```

ターミナルのプロジェクトルートにて、`gulp scripts` と入力すると、
dist/ 以下にコンパイルされた .js ファイルと .d.ts ファイルが作成されるようになりました。

続いて、作成された .js をまとめるため、gulp/tasks/ に webpack.js というタスクを追加しました。

- [webpack-stream の README](https://github.com/shama/webpack-stream) 
- [gulp + webpack + reactの最小構成](http://qiita.com/uryyyyyyy/items/6d7d29499efbca8c618e)

などを参考にさせていただきました。

```webpack.js
var gulp = require('gulp');
var webpack = require('webpack-stream');

gulp.task('webpack', function() {
    return gulp.src('dist/js/src/index.js')
        .pipe(webpack({
            output: {
                filename: 'build.js',
            },
            devtool: 'inline-source-map'
        }))
        .pipe(gulp.dest('.'));
});
```

ターミナルのプロジェクトルートにて、`gulp webpack` と入力すると、
プロジェクトルート直下に、build.js が作成されるようになりました。
プロジェクトルート直下の index.html をダブルクリックして、アプリの動作確認を行いました。

更に、ブラウザーで自動で開かれるように browser.js というタスクを追加しました。

```browser.js
var gulp = require('gulp');
var browserSync = require('browser-sync');

gulp.task('browser', function() {
    browserSync.init({
        server: '.',
        open: 'external'
    });
});

gulp.task('browser-reload', function () {
    browserSync.reload();
});
```

ターミナルのプロジェクトルートにて、`gulp browser` と入力すると、
アプリがブラウザーで自動的に起動するようになりました。

これらのタスクを連携させるため、gulpfile.js を以下のように変更しました。
`gulp` と一度入力するとブラウザで表示が行われ、以降はファイルに変更があると、
自動でコンパイルやビルドが行われ、ブラウザーが更新されるようになっているはずです.

```gulpfile.js
var gulp = require('gulp');
var runSequence = require('run-sequence');

require('require-dir')('./gulp/tasks', {recurse: true});

gulp.task('build', function() {
    runSequence('scripts', 'webpack')
});

gulp.task('server', function() {
    runSequence('build', 'browser')
});

gulp.task('default', ['server'], function() {
    gulp.watch('src/**/*', ['build']);
    gulp.watch('*.html', ['browser-reload']);
    gulp.watch('*.js', ['browser-reload']);
});
```

## GitHub への投稿と GitHub Pages の作成

GitHub にログインして、todo-list2 というレポジトリを作成（UserName.github.io は、作成済み）。

プロジェクトルート直下に以下のような .gitignore を作成。

```.gitignore
dist
node_modules
typings
.DS_Store
```

ターミナルのプロジェクトルートにて、以下のコマンドにより push しました。

```
git init
git add .
git commit -m 'first'
git remote add origin https://github.com/UserName/todo-list2.git
git push -u origin master
```

続いて、ブラウザで todo-list2 プロジェクトに gh-pages というブランチを作成しました。

[作成された GitHub Pages の TODO List アプリ](http://NariseT.github.io/todo-list2) にアクセスすると、ちゃんと使用することができました。