Get started Express + TypeScript する

## はじめに
どうしてもJavascriptでサーバーサイドの実装したかったのでExpress+TypeScriptのセットアップ。
特に嵌りポイントもなかったのですが備忘に。

## 前提条件
Node.jsとnpmのインストールは一通り終わってる前提です。

## 目指す姿
- TypeScriptでserver.tsを書いてserver.jsにトランスパイルできるようにする
- ちゃんとデバッグできるようにする

## 必要なモジュールをインストールする
### Express
この記事のテーマです。typesもまとめてインストールしてしまいます。

```shell
npm install --save express
npm install --save-dev @types/express
```

### TypeScript
TypescriptとLinterとwebpackにいれるloaderをインストールしておきます。ルールはairbnbで。

```shell
npm install --save-dev typescript ts-loader tslint tslint-loader tslint-config-airbnb
```

### Webpack
みんなが大好きなwebpackです。たくさんのjsファイルを1個にしてくれるすごいやつです。

```shell
npm install --save-dev webpack webpack-cli
npm install --save-dev webpack-node-externals    #warningの抑制
```

## 各種設定ファイル
### Webpackの設定
気をつけるのはtargetをnodeにすることと、externalにwebpack-node-externalsを指定するくらい。
webpack-node-externalsを指定しないと、`'"/Users/xxx/node_modules/@types/express/index"' has no default export`が出てうざいです。

```webpack.config.dev.js
const path = require('path');
const nodeExternals = require('webpack-node-externals');

module.exports = {
    mode: 'development',
    entry: './src/server.ts',     // src下に書いていくので　src/server.tsにしとく
    target: 'node',               // Module not found: Error: Can't resolve 'fs'とかいっぱい出たら、この行書き忘れ
    externals: [nodeExternals()], 
    devtool: 'inline-source-map',
    module: {
        rules: [
            {
                enforce: 'pre',
                loader: 'tslint-loader',
                test: /\.ts$/,
                exclude: [
                    /node_modules/
                ],
                options: {
                    emitErrors: true
                }
            },
            {
                loader: 'ts-loader',
                test: /\.ts$/,
                exclude: [
                    /node_modules/
                ],
                options: {
                    configFile: 'tsconfig.dev.json'
                }
            }
        ]
    },
    resolve: {
        extensions: [ '.ts', '.js' ]
    },
    output: {
        filename: 'server.js',
        path: path.resolve(__dirname, 'dist')
    }
};
```

```webpack.config.prod.js
const path = require('path');
const nodeExternals = require('webpack-node-externals');

module.exports = {
    mode: 'production',
    entry: './src/server.ts',     // src下に書いていくので　src/server.tsにしとく
    target: 'node',               // Module not found: Error: Can't resolve 'fs'とかいっぱい出たら、この行書き忘れ
    externals: [nodeExternals()], 
    module: {
        rules: [
            {
                enforce: 'pre',
                loader: 'tslint-loader',
                test: /\.ts$/,
                exclude: [
                    /node_modules/
                ],
                options: {
                    emitErrors: true
                }
            },
            {
                loader: 'ts-loader',
                test: /\.ts$/,
                exclude: [
                    /node_modules/
                ],
                options: {
                    configFile: 'tsconfig.dev.json'
                }
            }
        ]
    },
    resolve: {
        extensions: [ '.ts', '.js' ]
    },
    output: {
        filename: 'server.js',
        path: path.resolve(__dirname, 'dist')
    }
};
```

### tsconfig.jsonとtslint.jsonの設定
Requestなど必ずしもすべての引数を使うわけではないので`noUnusedParameters`はfalseに、インデントサイズは4にしておく(好み)。

```tsconfig.dev.json
{
  "compilerOptions": {
    "sourceMap": true,
    "noImplicitAny": true,
    "module": "es6",
    "target": "es5",
    "jsx": "react",
    "lib": ["es2018", "dom"],
    "moduleResolution": "node",
    "removeComments": true,
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": false,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "strictFunctionTypes": false
  }
}
```

```tsconfig.prod.json
{
  "compilerOptions": {
    "noImplicitAny": true,
    "module": "es6",
    "target": "es5",
    "jsx": "react",
    "lib": ["es2018", "dom"],
    "moduleResolution": "node",
    "removeComments": true,
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": false,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "strictFunctionTypes": false
  }
}
```

```tslint.json
{
    "extends": "tslint-config-airbnb",
    "rules": {
        "ter-indent": [true, 4]
    }
}
```

## 最後に
### ソースの追加
最後にソースの追加をします。

```src/server.ts
import * as Express from 'express';

const app = Express();

app.get(
    '/',
    (req: Express.Request, res: Express.Response) => {
        return res.send('Hello world.');
    });

app.listen(
    3000,
    () => {
        console.log('Example app listening on port 3000!');
    });

export default app;
```

### ビルドして起動
あとはビルドして起動するだけです。

```shell
webpack --config webpack.config.dev.js    # もちろん本番用ビルドはwebpack.config.prod.jsに変える
node dist/server.js
```

できあがったソース群はこちら
https://github.com/IgnorantCoder/typescript-express-sample