TypeScript + Node.js プロジェクトのはじめかた2020

# TL;DR

https://github.com/notakaos/typescript-node-base にアクセスして「Use this template」をクリックすると、以下の手順をベースとしたリポジトリが新規作成されます。

# この記事の趣旨

以下の設定を適用した TypeScript + Node.js のプロジェクトを作成します。

項目       | パッケージ
------------|----------
コンパイラ(トランスパイラ) | [typescript](https://www.typescriptlang.org/)
開発サポート | [ts-node](https://github.com/TypeStrong/ts-node) / [ts-node-dev](https://github.com/whitecolor/ts-node-dev) / [rimraf](https://github.com/isaacs/rimraf) / [npm-run-all](https://github.com/mysticatea/npm-run-all)
エディター設定 | [EditorConfig](https://editorconfig.org/)
バージョン管理 | [git](https://git-scm.com/)

# 動作環境

node と npm はインストール済みとします。

```bash
$ node -v
v12.18.3
$ npm -v
6.14.6
```

また、今回の記事はmacOSにて検証しております。

```bash
$ uname -v
Darwin Kernel Version 19.6.0: Sun Jul  5 00:43:10 PDT 2020; root:xnu-6153.141.1~9/RELEASE_X86_64

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.15.6
BuildVersion:   19G73
```

Linux環境だと手順はほぼ同じだと思いますが、Windows環境の場合は読み替えが必要になるかもしれません。

# 初期設定

TypeScript + Node.js プロジェクトを作成していきます。

## 1. プロジェクトディレクトリの作成

```bash:~/
mkdir typescript-node-base
cd typescript-node-base
```

## 2. git 初期化

```bash:~/typescript-node-base
git init
```

### .gitignore の生成

不要なファイルを Git にコミットしないようにするため、 `.gitignore` ファイルを生成します。

```bash:~/typescript-node-base
cat > .gitignore
```

以下をコピペして改行後に `Ctrl+D` を押下します。

```bash:~/typescript-node-base/.gitignore
# macOS
### https://raw.github.com/github/gitignore/07c730e1fccfe0f92b29e039ba149d20bfb332e7/Global/macOS.gitignore
.DS_Store
.AppleDouble
.LSOverride
Icon
._*
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk

# Linux
### https://raw.github.com/github/gitignore/07c730e1fccfe0f92b29e039ba149d20bfb332e7/Global/Linux.gitignore
*~
.fuse_hidden*
.directory
.Trash-*
.nfs*

# Windows
### https://raw.github.com/github/gitignore/07c730e1fccfe0f92b29e039ba149d20bfb332e7/Global/Windows.gitignore
Thumbs.db
ehthumbs.db
ehthumbs_vista.db
*.stackdump
[Dd]esktop.ini
$RECYCLE.BIN/
*.cab
*.msi
*.msm
*.msp
*.lnk

# node.js
### https://raw.github.com/github/gitignore/07c730e1fccfe0f92b29e039ba149d20bfb332e7/Node.gitignore
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pids
*.pid
*.seed
*.pid.lock
lib-cov
coverage
.nyc_output
.grunt
bower_components
.lock-wscript
build/Release
node_modules/
jspm_packages/
typings/
.npm
.eslintcache
.node_repl_history
*.tgz
.yarn-integrity
.env
.next
```

### (オプション) または gibo を使って .gitignore を生成する

* gibo: fast access to .gitignore boilerplate - https://github.com/simonwhitaker/gibo

.gitignore を生成するツール `gibo` を利用している場合は、以下のコマンドで前述の .gitignore と同じ内容が生成できます。

```bash:~/typescript-node-base
gibo dump macos linux windows node > .gitignore
```

あとは必要に応じて .gitignore を修正してください。

## 3. (オプション) EditorConfig の設定

* EditorConfig - https://editorconfig.org/

様々なエディターでの文字コードや改行コード、タブorスペース等の設定を共通化できる、 EditorConfig の設定を追加します。

```bash:~/typescript-node-base
cat > .editorconfig
```

以下をコピペして改行後に `Ctrl+D` を押下します。

```ini:~/typescript-node-base/.editorconfig
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_size = 2
indent_style = space
trim_trailing_whitespace = true

[Makefile]
indent_size = 4
indent_style = tab

[*.{md,markdown}]
insert_final_newline = false
trim_trailing_whitespace = false

[*.json]
insert_final_newline = false
```

`.editorconfig` はお好みで書き換えてください。

## 4. package.json の生成

```bash:~/typescript-node-base
npm init -y
```

`npm init -y` で package.json を生成するとバージョン番号がデフォルトで `1.0.0` になります。

個人的な好みですが、開発中は [セマンティック バージョニング 2.0.0](https://semver.org/lang/ja/)に合わせてバージョンを `0.1.0` としておきます。

```diff:~/typescript-node-base/package.json
{
  "name": "typescript-node-base",
- "version": "1.0.0",
+ "version": "0.1.0",
  "main": "index.js",
...
```

## 5. typescript パッケージの追加

```bash:~/typescript-node-base
npm install -D typescript @types/node@12
```

（注：`@types/node@<バージョン番号>` のバージョン番号部分はお使いのNode.jsのバージョンに合わせて変更してください）

typescriptパッケージをインストールしたらバージョンを確認します。

```bash:~/typescript-node-base
npx tsc --version
```

```bash:出力
Version 3.9.7
```

### tsconfig.json 生成

```bash:~/typescript-node-base
npx tsc --init
```

`tsc --init` を実行すると、 `tsconfig.json` が生成されます。
プロジェクトに合わせて tsconfig.json を修正します(以下はコメントを除いて表記しています)。

```diff:~/typescript-node-base/tsconfig.json
{
  "compilerOptions": {
-   "target": "es5",
+   "target": "ES2019",
    "module": "commonjs",
+   "sourceMap": true,
+   "outDir": "./dist",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
- }
+ },
+ "include": [
+   "src/**/*"
+ ],
}
```

## 6. Hello, World!

動作確認のため TypeScript の簡単なプログラムを作ってみます。

```bash:~/typescript-node-base
mkdir src
touch src/index.ts
```

`src/index.ts` をエディターで開き、以下の内容を入力して保存します。

```javascript:~/typescript-node-base/src/index.ts
function hello(name: string): string {
  return `Hello, ${name}!`;
}

console.log(hello("World"));
```

`src/index.ts` ファイルを保存したら、`typescript` パッケージに同梱する `tsc` コマンドを実行します。

```bash:~/typescript-node-base
npx tsc
```

すると、 `tsconfig.json` の設定に従って TypeScript から JavaScript への変換が行われ、`dist/index.js` と `dist/index.js.map` が生成されます。

```bash:~/typescript-node-base
ls dist
#=> index.js      index.js.map
```

生成された `index.js` を実行してみましょう。

```bash:~/typescript-node-base
node dist/index.js
```

以下のメッセージが表示されれば成功です。

```:実行結果
Hello, World!
```

## 7. 開発の効率をあげる (ts-node & ts-node-dev)

`tsc` コマンドでコンパイルして `node` でプログラムが実行できるようになりました。
しかし、ソースコードを修正するたびに `tsc` を実行し、さらにそのあと `node` コマンドを実行するのは手間がかかりますね。
開発効率をあげるため、 `tsc -> node` の実行を自動的に行ってくれる `ts-node` パッケージを追加します。

### `ts-node` パッケージの追加

```bash:~/typescript-node-base
npm install -D ts-node
```

パッケージが追加されたら `ts-node` コマンドを実行してみましょう。

```bash:~/typescript-node-base
npx ts-node src/index.ts
```

```bash:実行結果
Hello, World!
```

通常の `node` コマンドで JavaScript を実行するかのように、`ts-node` で TypeScript ファイルが実行できました。

### `ts-node-dev` パッケージの追加

`ts-node` で少し効率があがりました。ただ、ソースコードを修正するたび、毎回手動で実行する必要があります。

さらに開発効率をあげるため、ソースコードの変更を検知するたびに自動的に再実行してくれる `ts-node-dev` パッケージを追加します。

```bash:~/typescript-node-base
npm install -D ts-node-dev
```

パッケージが追加されたら `ts-node-dev` コマンドを実行してみましょう。

注: APIサーバーのように一度実行すると動き続けるプログラムではなく、この記事のHello Worldプログラムのように1度実行するとプロセスが終了するプログラムの場合は、`ts-node-dev` に `--respawn` オプションをつけます。

```bash
npx ts-node-dev --respawn src/index.ts
```

`ts-node-dev` が起動したら、エディターで `src/index.ts` を修正して保存します。

```diff:~/typescript-node-base/src/index.ts
function hello(name: string): string {
   return `Hello, ${name}!`;
}

- console.log(hello("World"));
+ console.log(hello("TypeScript"));
```

すると、ソースコードの変更を検知して、自動的にプログラムが再実行されます。

```bash:実行結果
Using ts-node version 8.10.2, typescript version 3.9.7
Hello, World!
[INFO] 18:43:47 Restarting: /Users/n_ohshiro/git/notakaos/typescript-node-base/src/index.ts has been modified
Using ts-node version 8.10.2, typescript version 3.9.7
Hello, TypeScript!
```

自動で再実行されました！

`ts-node-dev` を終了する時は `Ctrl+C` を押下します。

```bash
^C
```

### npm-scripts に `dev` と `dev:watch` を追加する

ts-node と ts-node-dev を簡単に呼び出せるようにするため package.json を修正します。

```diff:~/typescript-node-base/package.json
{
  "name": "typescript-node-base",
  "version": "0.1.0",
  "main": "index.js",
  "scripts": {
-    "test": "echo \"Error: no test specified\" && exit 1"
+    "dev": "ts-node src/index.ts",
+    "dev:watch": "ts-node-dev --respawn src/index.ts"
  },
  ...
```

修正して保存したら動作確認を行います。

```bash
# 1回実行
npm run dev

# 変更検知
npm run dev:watch
```

これで TypeScript で Node.js のプログラムが開発できるようになりました。

## 8. `rimraf` `npm-run-all` パッケージの追加と npm-scripts に `clean` / `tsc` / `build` / `start` を追加

`tsc` でビルドを行ったファイルを一括削除できるように、`rimraf` パッケージを追加します。
また、複数のnpm-scriptsのコマンドを実行できるように `npm-run-all` パッケージも併せて追加します。

```bash:~/typescript-node-base
npm install -D rimraf npm-run-all
```

そして、package.json を以下のように修正します。

```diff:~/typescript-node-base/package.json
{
  "name": "typescript-node-base",
  "version": "0.1.0",
-  "main": "index.js",
+  "main": "dist/index.js",
  "scripts": {
    "dev": "ts-node src/index.ts",
-    "dev:watch": "ts-node-dev --respawn src/index.ts"
+    "dev:watch": "ts-node-dev --respawn src/index.ts",
+    "clean": "rimraf dist/*",
+    "tsc": "tsc",
+    "build": "npm-run-all clean tsc",
+    "start": "node ."
  },
  ...
```

package.json を修正したら動作確認をしましょう。

```bash:~/typescript-node-base
# TypeScript -> JavaScript に変換
npm run build

# 生成されたJavaScriptを実行
npm run start
## または
npm start

# 生成されたファイルを削除
npm run clean
```

最終的にはビルドで生成された JavaScript ファイルを Node.js で動作させることになります。
`build` と `start` はそのためのものです。

## 9. ソースコードのバージョン管理

これまでのコードをgitにコミットしましょう。

tscコマンド実行後に生成される `/dist` はgitの対象外としたいので、.gitignoreファイルに以下の1行を追加します。

```:~/typescript-node-base/.gitignore
# 最後に以下の行を追加
/dist
```

```bash:~/typescript-node-base
git status
git add .
git commit -m "First commit"
```

これでgitへのコミットが完了しました。

あとは必要なパッケージや設定を行い、TypeScript + Node.js でのアプリケーション開発を楽しみましょう！

# 成果物

完成形のソースコードは以下になります。

* https://github.com/notakaos/typescript-node-base

**(2020/8/12 追記)** ESLintとPrettierを導入する手順を記事にしました。

* [TypeScript + Node.jsプロジェクトにESLint + Prettierを導入する手順2020 - Qiita](https://qiita.com/notakaos/items/85fd2f5c549f247585b1)

# 変更履歴

- 2020/8/12 ESLintとPrettierを導入する記事へのリンク追加
- 2020/8/11 GitHubのリポジトリをテンプレートリポジトリに変更
- 2020/8/11 タイトルを「TypeScript + Node.js プロジェクトのはじめかた2020」に変更
- 2020/8/11 TypeScript 3.9.7 にアップデート
- 2019/11/11 TypeScript 3.7.2 にアップデート
- 2019/9/10 TypeScript 3.6.2 にアップデート
- 2019/2/8 記事公開