Help us understand the problem. What is going on with this article?

TypeScript+Webpack+Node(Express)でファイル変更後にnodeを自動再起動する

はじめに

この記事はLinkbal Advent Calendar 2018の3日目の記事です。昨日は弊社CTOの開発組織の育て方 – エンジニア3人から30人へという、組織と事業が拡大していくことによる技術や採用の変遷のお話です。ぜひご一読いただければ幸いです。

リンクバルに新卒入社して2年目の水野(キンチキ)です。今年の10月からエンジニアではなくビジネス側(?)になったのですが、プライベートでも仕事でもコードはちょくちょく書いているので、もちろんアドベントカレンダーも書きます!

今回はTypeScript+Webpack+Node(Express)でNodeの再起動を自動で行う方法がわからず、あまり良いとは思わないながらも解決できた方法について書きます。

ちなみにリンクバルはTyepScriptを採用していない(!)です。学習コストは仕方ないとしても、型があるおかげでバグは間違いなく減ると思います。あと採用面での効果は絶対に+のはず(水野予測)。

いずれ使ってくれるといいなあ。

パッケージのインストール

最初の工程から説明します。

必要なパッケージを以下のコマンドでインストールします。
yarn addのオプションの-D--devと同じです。
lintは省いています。

$ mkdir sample && cd $_
$ yarn init -y # 初期化
$ yarn add -D @types/express typescript ts-loader webpack webpack-cli nodemon webpack-node-externals # パッケージインストール(devDependencies)
$ yarn add express # パッケージインストール(dependencies)

# npmを使う場合
$ npm init -y
$ npm i -D ...
$ npm i -S express

expresだけdependenciesにしていますが、devDependenciesでもいいかもしれません。
私はdependenciesにしないといけないパッケージがよくわかっていないです。。。

インストールしたパッケージの用途です。

  • @types/express: express用の型定義
  • typescript: TypeScript
  • ts-loader: webpackがTypeScriptをコンパイルできるようになるやつ
  • webpack, webpack-cli: webpack周り
  • nodemon: node再起動
  • webpack-node-externals: WARNING抑制(必須ではない)

tsconfigの作成

tscでtypescriptの設定ファイル(tsconfig)を作成します。

$ npx tsc --init

tsconfigを以下のようにします。
これは開発用なので、本番環境用を作成する際は別途ファイル作成するなどして内容を適宜変更してください。

./tsconfig.js
{
  "compilerOptions": {
    "sourceMap": true,
    "noImplicitAny": true,
    "module": "commonjs",
    "target": "es5",
    "lib": [
      "es2018",
      "dom"
    ],
    "moduleResolution": "node",
    "removeComments": true,
    "strict": true,
    "noUnusedLocals": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "strictFunctionTypes": false
  }
}

webpack.configの作成

touch webpack.configやエディアでファイルを作成し、以下のようにしてください。

エントリーポイントは./src/server.tsとし、最終的にビルドされるファイルはdist/server.jsとしています。
watchをtrueにしておくことでファイルの変更を検知します。

こちらも開発用なので、本番環境用を作成する際は別途ファイル作成するなどして内容を適宜変更してください。

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

module.exports = {
  watch: true,
  mode: 'development',
  entry: './src/server.ts',
  target: 'node',
  externals: [nodeExternals()],
  devtool: 'inline-source-map',
  module: {
    rules: [
      {
        loader: 'ts-loader',
        test: /\.ts$/,
        exclude: [
          /node_modules/
        ],
        options: {
          configFile: 'tsconfig.json'
        }
      }
    ]
  },
  resolve: {
    extensions: ['.ts', '.js']
  },
  output: {
    filename: 'server.js',
    path: path.resolve(__dirname, 'dist')
  }
};

nodemon.jsonの作成

touch nodemon.jsonなどで作成し、以下のようにしてください。

watch対象をwebpackのoutputに指定しているディレクトリ(この場合dist)にするのがポイントです。こうすることで、コンパイル後に自動でnodeを再起動してくれます。

./nodemon.json
{
  "restartable": "rs",
  "watch": [
    "dist"
  ],
  "env": {
    "NODE_ENV": "development"
  }
}

expressの実装

srcディレクトリを作り、そこにserver.tsを作成します。/へのgetリクエストに文字列を返す処理だけ書いておきましょう。

$ mkdir src
$ touch src/server.ts
src/server.ts
import * as express from 'express';

const app: express.Application = express();
const router: express.Router = express.Router();
const port = process.env.PORT || 3000;

router.get('/', (req: express.Request, res: express.Response) => {
  res.send('Hello, Express with TypeScript!');
});
app.use('/', router);

app.listen(port, () => {
  console.log(`Listening at http://localhost:${port}/`);
});

最後にpackage.jsonにscriptsを追加しましょう。
webpackとnodemonを&で繋いで同時起動しています。tsファイルが変更されたらwebpackがコンパイルし、nodemonがnodeを再起動します。

./package.json
{
  "name": "express-test",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "dev": "nodemon dist/server.js & webpack --config webpack.config.js"
  },
  "devDependencies": {
  "以下略"
}

ここまできたら yarn run dev で動かすことができます。

auto-restart-node.gif

ファイルを編集したらnodeが再起動し、リロードしたら反映されていますね!

おわりに

この方法だとエラー箇所がわかりづらかったり、webpackがクラッシュしたらプロセスが残ったりしますが、あまりいい方法が見つからなかったのでいったんこれで開発しています。この方法は手軽なのがウリです。webpack-dev-serverでうまいことホットリロードできると思いましたが、やり方がわかりませんでした。この方法でも支障は特にありません。

プロセスが残っていたら以下のコマンドで一括killしましょう。

kill -9 `ps -ef | grep nodemon |  awk '{print $2;}'`

リンクバルでTypeScriptが採用される日を待っています(強い意思はない)。

参考

このページも結構参考にしたのですが、今は見れなくなっています。
https://dev.to/briandgls/using-typescript-with-express--e0k

ts-nodeを使ったりすればホットリロードできそうですね。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away