TypeScriptでasync/await (webpackビルド)

# やりたいこと

* TypeScriptでasync/awaitを使う
* ライブラリの型定義も取得したい
* webpackでビルド
* ついでにgulpタスクとして動かしたい

[TypeScript の async/await をいますぐ使う - Qiita](http://qiita.com/mizchi/items/f0866cf1c239f81e697a) でやってる方法のwebpack版。

# 方針

* [awesome-typescript-loader](https://github.com/s-panferov/awesome-typescript-loader)で一気にできそうだけどやり方がよくわからなかった
* Browserify+tsify+babelifyでもできそうだけどやり方がry)

結局、[ts-loader](https://github.com/TypeStrong/ts-loader)と[babel-loader](https://github.com/babel/babel-loader)を使った。ES6を経由しつつBabelでES5にする。

ts -> (ts-loader) -> es6 -> (babel-loader) -> es5

# 必要環境インストール

npmでごっそり取る。

```
$ npm init
$ npm i -D gulp typescript typings webpack-stream ts-loader babel-loader
$ npm i -D babel-core babel-preset-es2015 babel-preset-stage-0
$ npm i -S babel-polyfill
```

# typingsで型定義取得

[tsdが非推奨になった](https://github.com/DefinitelyTyped/tsd/issues/269)ことに注意。[typings](https://github.com/typings/typings)を入れる。

```
$ npm i -g typings
$ typings init
$ typings i lodash -S -A
$ npm i -S lodash
```

型定義だけ取得するので`--save (-S)`と`--ambient (-A)`を指定しとけばOK。
そのうちtypingsでライブラリ本体も取れるようになるのかな。
関係ないけどlodashは型定義だけで17000行以上あってビビる。

# エントリファイル作成

起点となるスクリプトとしてとりあえずsrc/entry.tsとして書く。
今回はCommonJSライブラリを作成したかったので、exportで外部に出すライブラリを指定している。

```ts:src/entry.ts
import {Foo} from './Foo';
import {Bar} from './Bar';
export = {Foo:Foo, Bar:Bar};
```

ちなみに三行目を`export = {Foo, Bar};`にしたらライブラリ利用時にReferenceErrorになる。なんでだ。

# TypeScriptコンパイル設定

tsconfig.jsonを書く。

```json:tsconfig.json
{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es6"
  },
  "files": [
    "typings/browser.d.ts",
    "src/entry.ts",
    "src/Foo.ts",
    "src/Bar.ts"
  ]
}
```

BabelでES5にするので、TypeScriptのtargetはes6でいい。
typings/(browser|main).d.tsもfilesに追加。

# webpackの設定

webpack.config.jsを書く。

**追記:** ライブラリを作る場合はexternalsを追加しておこう。

```js:webpack.config.js
module.exports = {
  entry: ['babel-polyfill', './src/entry.ts'], // gulp.srcで指定する場合不要
  resolve: {
    extensions: ['', '.ts', '.js']
  },
  output: {
    path: __dirname + '/lib',
    filename: 'bundle.js',
    libraryTarget: 'commonjs' // CommonJSとして出力
  },
  module: {
    loaders: [
      {
        test: /\.ts(x?)$/,
        loader: 'babel-loader?presets[]=es2015,presets[]=stage-0!ts-loader'
      }
    ]
  },
  externals: {
    "babel-polyfill": "babel-polyfill",
    "lodash": "lodash"
  }
};
```

babelでasync/awaitを使うにはbabel-polyfillの同梱とstage-2以上のpresets指定が必要。
loaderは"!"で繋げる必要がある。この場合query使えないので、presetsはloader記述に埋める。
loaderを単に並べたりpreLoader使うのではbabel-loaderがうまく走らなかった。
ここでだいぶハマった...

**追記:** さらに結構すっきりさせられる事がわかった。

* ``loader``の代わりに``loaders``プロパティを使えば"!"の代わりに配列で指定できる
* .babelrcを書いておくとbabelが設定を読みにいってくれる
* ``babel-loader``の代わりに``babel``と書ける

これらを使えば、

```js:webpack.config.js(一部)
  // ...
    loaders: [
      {
        test: /\.ts(x?)$/,
        loaders: ['babel', 'ts']
      }
    ]
  // ...
```
```json:.babelrc
{
  "presets": ["es2015", "stage-0"]
}
```

こんなにすっきり！

# webpackでビルド

この時点でwebpackを直接叩いてビルドできる。簡単にやるならこれで。

```
$ npm i -g webpack
$ webpack
```

# gulpでビルド

gulpタスクから叩きたいとき。

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

gulp.task('webpack', () => {
  return gulp.src(['babel-polyfill', './src/entry.ts'])
    .pipe(webpack(require('./webpack.config.js')))
    .pipe(gulp.dest('lib'));
});
```

```text:ビルド
$ gulp webpack
```

webpack-streamでgulp.src指定するときはwebpack.config.jsのentryは消しておくこと。
残しておいたらファイルサイズでかくなったので、多分どっかでダブってる。

そのまんまwebpack使うなら普通に呼べばOK。

```js:gulpfile.js
var gulp = require('gulp');
var gutil = require('gulp-util');
var webpack = require('webpack');

gulp.task('webpack', (callback) => {
  webpack(require('./webpack.config.js'), (err, stats) => {
    if(err) throw new gutil.PluginError('webpack', err);
    callback();
  });
});
```

```text:ビルド
$ npm i -D webpack
$ gulp webpack
```

以上。いやー疲れた。
いろんな設定をいろんなところに書けるから、何がいい方法かさっぱりわからんね。
もっといい方法あったら教えて下さい。