ほぼコレを参考にしています
構成
/app |- /dist # build されたアプリの出力先 |- /src | |- index.ts # express entrypoint |- /webpack | |- base.config.js # 共通設定 | |- dev.config.js | |- prod.config.js |- nodemon.json |- package.json |- tsconfig.json
- 開発中は nodemon で ts-node を実行して src 内の TypeScript を監視して開発
- development / production それぞれのモードで build して確認できるようにする
開発環境 Express + TypeScript を nodemon で監視しながら動作させる
$ npm install --save-dev @types/express typescript ts-node nodemon $ npm install --save express
TypeScript の変換方法の設定
tsconfig.json
{ "compilerOptions": { "strict": true, "module": "commonjs", "target": "es2017", "sourceMap": true, // import * as _ from '_' はエラー、代わりにimport _ = require('_') を使う "esModuleInterop": true, // 暗黙的にanyになる値をエラーにする "noImplicitAny": true, // tscのモジュール解決の方法 "moduleResolution": "node", // コメントを削除する /*! から始まるコメントは残る "removeComments": true, // import時にファイルパスの文字列で大文字小文字を区別するかどうか "forceConsistentCasingInFileNames": true, // 以前コンパイルを実行したコードと現在のコードとの差分を検出して、必要なファイルだけをコンパイルする "incremental": false, // コンパイルした js ファイルの出力先 "outDir": "dist", // 相対的なカレントディレクトリをどこにするかの指定値、./の場合はtsconfig.jsonが置いてあるディレクトリ "baseUrl": "src", "paths": { "*": [ "node_modules/*", "src/types/*" ] }, }, // コンパイルする対象ファイルの場所 "include": [ "src/**/*" ] }
nodemon の設定
nodemon.json
{ "restartable": "rs", "env": { "NODE_ENV": "dev" }, "watch": [ "src" ], "ext": "js, ts, json", "ignore": [ "tests/**/*.ts" ], "exec": "ts-node ./src/index.ts" }
TypeScript を監視対象にするために ext
オプションを使います。
cf. Node.js + TypeScript nodemon + ts-node で変更が watch されず ホットリロードされないにハマる - かもメモ
Express
localhost:3000
にアクセスしたら hello world するだけのアプリ
/src/index.ts
import express from 'express'; const PORT = 3000; const app = express(); const router = express.Router(); // Middleware app.use(express.json()); app.use(express.urlencoded({ extended: true })); router.get('/', async (req: express.Request, res: express.Response): Promise<void> => { res.send('hello world'); }, ); app.use('/', router); app.listen(PORT, () => console.log(`listening on port http://localhost:${PORT}`)); export default app;
実行スクリプトの作成
package.json
にスクリプトを追加
"scripts": { "dev": "nodemon -L" }
$ npm run dev
を実行して localhost:3000
にアクセス。
「hello world」が表示されていて、/src/index.ts
を変更したら変更がホットリロードで反映されるようになっていれば OK
Webpack での build 環境の作成
パッケージのインストール
$ npm install --save-dev webpack webpack-cli webpack-node-externals webpack-merge ts-loader
webpack.config の作成
development, production 共通で使用する設定
/webpack/base.config.js
const webpack = require('webpack'); const nodeExternals = require('webpack-node-externals'); const path = require('path'); const BUILD_ROOT = path.join(__dirname, '../dist'); const SRC_ROOT = path.join(__dirname, '../src'); module.exports = { context: SRC_ROOT, entry: path.resolve('src', 'index.ts'), externals: [nodeExternals()], output: { filename: 'server.js', path: BUILD_ROOT, }, module: { rules: [ { test: /\.ts$/, exclude: /node_modules/, loader: 'ts-loader', options: { configFile: 'tsconfig.json', }, }, ], }, resolve: { extensions: ['.ts', '.js', '.json'], } };
development mode
/webpack/dev.config.js/
const baseConfig = require('./base.config.js'); const { merge } = require('webpack-merge'); const config = merge(baseConfig, { mode: 'development', devtool: 'inline-source-map', devServer: { contentBase: 'dist', host: '0.0.0.0', port: 3000, }, }); module.exports = config;
production mode
/webpack/prod.config.js
const baseConfig = require('./base.config.js'); const { merge } = require('webpack-merge'); const config = merge(baseConfig, { mode: 'production', }); module.exports = config;
build 用の npm-script を作成
package.json
"scripts": { "dev": "nodemon -L", "build:dev": "NODE_ENV=dev webpack --config ./webpack/dev.config.js", "build": "NODE_ENV=prod webpack --config ./webpack/prod.config.js", "start:dev": "npm run build:dev && node dist/server.js", "start": "npm run build && node dist/server.js" }
$ npm run start:dev
, $ npm run start
をそれぞれ実行して build, localhost:3000
でアプリが表示されていればOK
ESLint, Prettier
お好みで。
パッケージのインストール
npm isntall --save-dev eslint eslint-config-prettier eslint-plugin-prettier \ @typescript-eslint/eslint-plugin @typescript-eslint/parser prettier
ESLint の設定
.eslintrc.js
module.exports = { parser: '@typescript-eslint/parser', extends: [ 'plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended', 'prettier/@typescript-eslint', ], rules: { 'newline-before-return': 'error', 'no-console': 'warn', 'no-var': 'error', }, };
Prettier の設定
.prettierrc
{ "bracketSpacing": true, "printWidth": 80, "semi": true, "singleQuote": true, "trailingComma": "all", "useTabs": false, }
VS Code ファイル保存時に自動的に ESLint, Prettier を実行させる
$ mkdir .vscode $ touch .vscode/settings.json
.vscode/settings.json
{ "eslint.enable": true, "eslint.validate": [ "javascript", "javascriptreact", "typescript", "typescriptreact" ], "editor.codeActionsOnSave": { "source.fixAll.eslint": true }, "files.exclude": { "**/node_modules": true }, "search.exclude": { "**/node_modules": true, } }
JavaScript / TypeScript ファイルに ESLint のエラーの表示・保存時に自動整形されるようになっていればOK
所感
快適 Express 開発環境ができました!
Webpack でコンパイルしているので開発・本番環境の切替も楽そうです。
GitHub にテンプレートとして作っておくと便利そう… (あとでやる)
Next Step Express を AWS Lambda にデプロイする serverless に挑戦していきたいです!
[参考]
- Typescript + Express + Webpackで作る、node.jsサーバー環境構築入門 - Qiita
- webpack-node-externals - npm
- webpack-merge - npm
- アーティスト:さよならポニーテール
- 発売日: 2014/03/05
- メディア: CD