今どきなオレオレTypeScript開発環境


TypeScriptでの開発環境を準備したので自分的なメモ。

TypeScriptをがっつり使ったことはなく、普段はES6使いなのだけど
ふと、やっぱり型があった方がいいなとか、Interfaceあった方がいいな、と思い始めたのでTypeScriptを使ってみようかと思った。

## やりたいこと
TypeScriptからES6形式に書き出しをしてBabelでトランスパイラしたいと思った。
(Babelは便利だけど個人的にかゆい所に手が届かない印象）

ついでにTypeScriptのLintも[Tslint](https://palantir.github.io/tslint/)を使ってしようと思う。

[webstorm](https://www.jetbrains.com/webstorm/)や[Atom](https://atom.io/)のプラグイン使ってIDE系が自動でLintやってくれる場合もあるけど、これだとIDEに依存するのでクソ過ぎるので論外。

それと最近っぽいくgulpファイル系も
**Babel**で書いてみる。

## まずインストール

取り敢えずインストールしないと始まらないのでインストールする。
**Node.js**はインストールされてる体で進めます。

Node.jsのインストールは[こちら](http://qiita.com/HayneRyo/items/326de7231d907447834d)


### 1. npm初期化、package.jsonの生成


```ターミナル
npm init
```

この後、色々と聞かれるから`yes`とタイプするか`Enterキー`を押せばOK。


### 2. 必要なモジュールをインストール

今回はやりたいこととしてBabel（ES6）でgulpfile.jsを記載してTypeScript（Tslintでエラー確認）→Babel→JSに書き出すのですが
**Webpack**とゆう依存解決するツールとBabelとゆうJavaScriptコンパイラを使っていこうかと思います。

なので主に
- gulp
- gulp-babel
- webpack
- babel-loader
- babel-preset-es2015
- babel-preset-stage-0
- ts-loader
- tslint-loader

をインストールします。

`Webpack + TypeScript`でES6に変換させるのに[ts-loader](https://github.com/TypeStrong/ts-loader)とゆうのを使います。これもインストールします。

TypeScriptから吐き出されたBabel（ES6）をJavaScriptで吐き出すには`webpack + babel-loader`でES6をビルドするみたいなので下記をインストールします。

参考：[webpack + babel-loaderでES6デビューしつつ、gulpもES6で書く](http://qiita.com/inureo/items/6ac74fb19e12f395e4c1)


preset系はBabelの`import`とかを使えるようにするためのものです。



`ts-loader`と`tslint-loader`はwebpackで使うためのものです。


```ターミナル
npm i babel babel-core babel-loader  babel-polyfillbabel-preset-es2015 babel-preset-stage-0 gulp gulp-babel gulp-load-plugins ts-loader tsd tslint-loader typescript typings webpack webpack-dev-middleware webpack-hot-middleware --save-dev
```

でインストールできます。

`package.json`が下記のように生成されたかと思います。

```package.json

{
  "name": "ts_sample",
  "version": "1.0.0",
  "description": "none",
  "main": "index.js",
  "scripts": {
    
  },
  "keywords": [
    "typescript",
    "webpack"
  ],
  "author": "HOGE",
  "license": "ISC",
  "devDependencies": {
    "babel": "6.5.2",
    "babel-core": "6.7.2",
    "babel-loader": "6.2.4",
    "babel-preset-es2015": "6.6.0",
    "babel-preset-stage-0": "6.5.0",
    "gulp": "3.9.1",
    "gulp-babel": "6.1.2",
    "gulp-load-plugins": "1.2.0",
    "ts-loader": "0.8.1",
    "tsd": "0.6.5",
    "tslint": "3.6.0",
    "tslint-loader": "2.1.3",
    "typescript": "1.8.7",
    "typings": "0.7.9",
    "webpack": "1.12.14",
    "webpack-dev-middleware": "1.5.1",
    "webpack-hot-middleware": "2.10.0"
  },
  "dependencies": {
    "typings": "0.7.9"
  }
}

```

- webpack-dev-middleware
- webpack-hot-middleware

上記はwebpack系の話しになってしまうので話しは端折ります。

参考：[Webpack はじめの一歩](http://qiita.com/kompiro/items/8337f28271b66957780e)

## webpackの設定をしていく
### 1.webpackの設定ファイルとgulpタスクをBabel（ES6）で記載していく。

gulpタスクをBabelで記載していこうと思います。
まずフォルダ構成はこんな感じにしてみました。
（ツッコミどころは満載かもですが、まーこんな感じで..）

```フォルダ
作業フォルダ
├── app
│   ├── js
│   │   ├── main.js（webpackから吐き出されるJS）
│   │   └── main.map
│   └── ts
│       └── main.ts
├── gulp
│   ├── tasks
│       └── ts.js
├── gulpfile.babel.js
├── package.json
├── tsconfig.json
├── tsd.json
├── tslint.json
├── webpack.config.babel.base.js
└── webpack.config.babel.development.js
```

まず`webpack`系を記載していきます。

### 2.webpackの元ファイルを作る
webpack系の設定ファイルを作っていきます。

`作業フォルダ`のルートに`webpack.config.babel.base.js`とゆうファイルを作り、下記の様に書きます。

```webpack.config.babel.base.js
import path from 'path';

export default {
  contentBase: path.resolve(__dirname, 'app'),
  cache: true,
  entry: [],
  output: {
  	// 吐き出しさき
  	// 今回は作業フォルダ/app/js/内に吐き出しさせる。
    path: __dirname + '/app/js/',
    publicPath: '/js/',
    filename: '[name].js',
    chunkFilename: '[chunkFilename].js',
    sourceMapFilename: '[name].map'
  },
  module: {
  	// ここでTypescriptのTsLintを設定
    preLoaders: [{
      test: /\.ts(x?)$/,
      exclude: /(node_modules|bower_components)/,
      include: __dirname,
      loader: 'tslint'
    }],
    loaders: [{
      test: /\.ts(x?)$/,
      loader: 'babel-loader?presets[]=es2015,presets[]=stage-0!ts-loader',
      include: __dirname,
      sourceMap: '',
      exclude: /(node_modules|bower_components)/
    }]
  },
  resolve: {
    extensions: ['', '.tsx', '.ts', '.js', 'jsx']
  }
}


```

これでwebpackの設定ファイルができたかと思います。

### 3.webpackでentryポイント等の追記
次にwebpack側にentryポイントとかの記載をします。

`作業フォルダ`のルートに`webpack.config.babel.development.js`を作り下記の様に記載する。

```webpack.config.babel.development.js
import baseConfig from './webpack.config.babel.base';
import webpack from 'webpack';

const config = Object.create(baseConfig);

config.entry = [
  'webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000&reload=true',
  // ここにTypescriptのentryポイントを記載
  './app/ts/main.ts'
];
config.debugMode = true;
config.devtool = '#source-map';

// webpackのプラグインを設定
config.plugins = [
  new webpack.optimize.OccurenceOrderPlugin(),
  new webpack.HotModuleReplacementPlugin(),
  new webpack.NoErrorsPlugin(),
  new webpack.DefinePlugin({
    'process.env.NODE_ENV': JSON.stringify('development')
  })
];

export default config;

```

## Babel（ES6）でgulpfileを書いていく
gulpfileを`Babel`（ES6）で書いていきます。

まず`Webpack`経由で`Typescript`→`Babel（ES6）`→`JavaScript`のタスクを作ります。

#### ts.jsを作る
タスクだけを記載するJSファイルを作ります。
`作業フォルダ`/gulp/tasks/に
**ts.js**としてファイルを作成して下記の様に記載する。


```ts.js
import gulp from 'gulp';
import gulpLoadPlugins from 'gulp-load-plugins';
import webpack from 'webpack';
import config from '../../webpack.config.babel.development';

const $ = gulpLoadPlugins();

/**
 * gulp ts で実行できる
 */
gulp.task('ts', () => {
  const setting = webpack(config);
  setting.run((error, stats) => {
    if(error){
      throw new Error('webpack something wrong :( ERROR has occured.');
    }
    // webpackのコンソールがいい感じになる
    $.util.log(stats.toString({
      colors: true,
      version: false,
      hash: false,
      timings: false,
      chunks: true,
      chunkModules: false
    }));
  })
});

```

webpackを走らせるタスクができたので今度は
`作業フォルダ`のルートに
**gulpfile.babel.js**を作って下記のように記載します。

```gulpfile.babel.js
import './gulp/tasks/ts';

```

## TypeScriptをBabel（ES6）で吐き出す準備をする。（tsconfig.json）

タスクまでは作ったけどこれだけじゃダメなので
TypeScriptでES6を吐き出し許可みたいなのをしないといけないので

`作業フォルダ`に
**tsconfig.json**を作成し下記のようにする。

```tsconfig.json
{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "removeComments": true,
    "noEmitOnError": false,
    "sourceMap": false
  },
  "filesGlob": [
    "**/*.ts",
    "**/*.tsx",
    "!node_modules/**"
  ],
  "compileOnSave": true,
  "exclude": [],
  "files": [
    "app/ts/main.ts"
  ]
}

```

targetを`es6`にしてあげるのがみそかと！

## .babelrcの設定をする。

タスクもできたし、TypeScriptの準備もできたのでターミナルで

```ターミナル
gulp ts
```
と打ってみる。


``` ターミナル
/作業フォルダ/gulpfile.babel.js:1
(function (exports, require, module, __filename, __dirname) { import './gulp/tasks/ts';

```
とエラーが出る。
これはgulpfileがbabelで書かれてるエラーなので、エラーが出ないように
`作業フォルダのルート`に
**.babelrc**とゆう名前で生成して下記の様に記載する。

```.babelrc
{
  "presets": ["es2015"]
}
```

## tslintを設定する。
TypeScriptのエラーを検出するためにtslintの設定をします。
エラーの設定ファイルがあるので
`作業フォルダのルート`に
**tslint.json**として保存します。

これはJSLintの設定ファイルと似た様な感じなのでルールは個人での好みがあるかと思います。
ひとまず、自分のはこんな感じで保存してます。

```tslint.json
{
  "rules": {
    "align": [
      false,
      "parameters",
      "arguments",
      "statements"
    ],
    "ban": false,
    "class-name": true,
    "comment-format": [
      false,
      "check-space",
      "check-lowercase"
    ],
    "curly": true,
    "eofline": true,
    "forin": true,
    "indent": [
      true,
      "spaces"
    ],
    "interface-name": true,
    "jsdoc-format": true,
    "label-position": true,
    "label-undefined": true,
    "max-line-length": [
      false,
      140
    ],
    "member-access": false,
    "member-ordering": [
      false,
      "public-before-private",
      "static-before-instance",
      "variables-before-functions"
    ],
    "no-any": false,
    "no-arg": true,
    "no-bitwise": false,
    "no-conditional-assignment": true,
    "no-consecutive-blank-lines": false,
    "no-console": [
      true,
      "debug",
      "info",
      "time",
      "timeEnd",
      "trace"
    ],
    "no-construct": true,
    "no-constructor-vars": true,
    "no-debugger": true,
    "no-duplicate-key": true,
    "no-duplicate-variable": false,
    "no-empty": true,
    "no-eval": true,
    "no-inferrable-types": false,
    "no-internal-module": true,
    "no-null-keyword": false,
    "no-require-imports": true,
    "no-shadowed-variable": false,
    "no-string-literal": true,
    "no-switch-case-fall-through": true,
    "no-trailing-whitespace": true,
    "no-unreachable": true,
    "no-unused-expression": true,
    "no-unused-variable": false,
    "no-use-before-declare": true,
    "no-var-keyword": true,
    "no-var-requires": true,
    "object-literal-sort-keys": false,
    "one-line": [
      true,
      "check-open-brace",
      "check-catch",
      "check-else",
      "check-finally",
      "check-whitespace"
    ],
    "quotemark": [
      true,
      "single",
      "avoid-escape"
    ],
    "radix": true,
    "semicolon": [
      true,
      "always"
    ],
    "switch-default": true,
    "trailing-comma": [
      false,
      {
        "multiline": "always",
        "singleline": "never"
      }
    ],
    "triple-equals": [
      true,
      "allow-null-check"
    ],
    "typedef": [
      true,
      "call-signature",
      "parameter",
      "arrow-parameter",
      "property-declaration",
      "variable-declaration",
      "member-variable-declaration"
    ],
    "typedef-whitespace": [
      true,
      {
        "call-signature": "nospace",
        "index-signature": "nospace",
        "parameter": "nospace",
        "property-declaration": "nospace",
        "variable-declaration": "nospace"
      }
    ],
    "use-strict": [
      true,
      "check-module",
      "check-function"
    ],
    "variable-name": [
      false,
      "check-format",
      "allow-leading-underscore",
      "ban-keywords"
    ],
    "whitespace": [
      false,
      "check-branch",
      "check-decl",
      "check-operator",
      "check-separator",
      "check-type"
    ]
  }
}

``` 

細かいルールの設定はまだ追いきれてませんが
下記が参考になります。

- [tslint](https://www.npmjs.com/package/tslint)
- [tslintの各オプションの意味一覧](http://anton0825.hatenablog.com/entry/2015/07/06/000000)

## タスク実行してみる。

ターミナルなるで

```ターミナル
gulp ts
```

とたたくと、

```ターミナル
ts-loader: Using typescript@1.8.7 and 作業フォルダ/tsconfig.json
[17:58:09]    Asset    Size  Chunks             Chunk Names
 main.js  107 kB       0  [emitted]  main
main.map  117 kB       0  [emitted]  main
chunk    {0} main.js, main.map (main) 82.6 kB [rendered]

```
と出て無事に`作業フォルダ/app/main.js`に吐き出しされた。

めでたしめでたし。

あくまで、個人用のメモなので責任は負いかねます。