TypeScript 3.0 がリリースされました。
追加機能のひとつ、Project references は、ちょうど仕事で「どうするのがいいの?」と迷ってたところだったので、さっそくやってみました。
話としてはよくある、 複数のプロジェクトから参照される "共通プロジェクト" の在り方 です。
Project Reference 適用以前
Project Reference 適用前(つまり現状)は、次のような構成になっていました(説明簡略化のため、client -> shared のみを書いてますが serverside からも shared を参照しています)。
root
├── client
│ ├── tsconfig.json
│ └── src
│ └── main.ts
└── shared
└── src
└── calc.ts
shared の calc.ts
export function calcAdd(x: number, y: number): number {
return x + y;
}
client の main.ts
import { calcAdd } from '../../shared/src/calc';
console.log(calcAdd(1, 2)); // = 3
client の tsconfig.json
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"outDir": "./dist",
"strict": true,
"esModuleInterop": true
}
}
shared/
配下 は ただのファイル置き場 で、client から相対パスで calc.ts
を参照しているに過ぎません。
これを tsc -b client/tsconfig.json
した結果は次のようになります。
root
├── dist
│ ├── client
│ │ └── src
│ │ └── main.js
│ └── shared
│ └── src
│ └── calc.js
├── client
│ └─-
└── shared
└─-
これはイケてないと思いつつ開発してきましたが、これを Project reference に変えてみます。
Project reference 適用後
ではプロジェクト参照を使ってみます。TypeScript Version 3.0.1 で試しています。
まず、 shared/ をプロジェクト化するために tsc --init
で tsconfig.json
を作り、内容を次のようにします。
shared の tsconfig.json
{
"compilerOptions": {
// tsc --init で既定で設定されてた項目
"target": "es5",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
// あとから追加した項目
"outDir": "../dist/shared",
"rootDir": "./src",
"composite": true,
"declaration": true,
}
}
"composite": true
がプロジェクト参照のために必要な項目で、"declaration": true
は、型定義ファイルを出力するために必要です(よね?)。outDir
と rootDir
は出力される .js ファイルの場所を調整するために設定しました。
次に client 側の tsconfig.json
を修正します。
client の tsconfig.json
{
"compilerOptions": {
// tsc --init で既定で設定されてた項目
"target": "es5",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
// あとから追加した項目
"outDir": "../dist/client",
"rootDir": "./src",
// さらに追加した相対パス地獄を防ぐための項目
"baseUrl": "./",
"paths": {
"shared/*": [
"../dist/shared/*"
]
}
},
// あとから追加した項目
"references": [
{ "path": "../shared" }
]
}
こちらには、 "references"
を追加し、shared への参照を設定します。これがプロジェクト参照のメインですね。
baseUrl
と paths
は、 "relative path hell" を回避するための設定です。
を見てやってみました。
最後に、client の main.ts
の import
文を書き換えます。
client の main.ts
import { calcAdd } from 'shared/calc';
console.log(calcAdd(1, 2)); // = 3
import は、shared プロジェクトのビルド結果である ./dist/shared
を参照するようにしますが、 先に baseUrl
と paths
で shared/*
に ../dist/shared/*
をマッピングさせているので、ここでは from 'shared/calc'
だけで済みます。
ではビルドしてみましょう。
tsc -b client/tsconfig.json
を実行します。ポイントは、shared もプロジェクトなのにそれは含めていない、ということです。
ビルド結果を含むディレクトリ全体は次のようになります。
root
├── client
│ ├── tsconfig.json
│ └── src
│ └── main.ts
├── shared
│ ├── tsconfig.json
│ └── src
│ └── calc.ts
└── dist
├── client
│ └── main.js
└── shared
├── calc.js
└── calc.d.ts
なんだかそれっぽくなった気がします。
tsc -b client/tsconfig.json
としたのに、プロジェクト参照に設定されている shared 側も(先に)ビルドされて dist/shared
に出力されています。
client の tsconfig.json
には "rootDir": "./src"
を設定したので、好き勝手に別の親ディレクトリにある .ts ファイルを参照することができなくなり、秩序が守られる気がします。
冒頭の説明には、もっとたくさんのオプションについて説明がありますが、とりあえず以上です。