npmのworkspace と tsconfig の設定方法の確認

TypeScript のプロジェクト参照
{
"compilerOptions": {
// The usual
},
"references": [
{ "path": "../src" }
]
}
参照したいプロジェクトのtsconfig.jsonへのパスを指定することで、outDirに設定された出力ファイルの
.d.ts を読み込む。 { "path": "../src/tsconfig.build.json" }
のように違う tsconfig を紐づけることも可能
-b (--build) オプションは、references の参照を元に必要に応じて事前にビルドをしてくれる
> tsc -b # Use the tsconfig.json in the current directory
> tsc -b src # Use src/tsconfig.json
> tsc -b foo/prd.tsconfig.json bar # Use foo/prd.tsconfig.json and bar/tsconfig.json

プロジェクトを指定した上でのコンパイル
$ tsc -p src/tsconfig.json
references は見ないで本プロジェクト自体のコンパイルが動く。正しくコンパイルするには参照プロジェクトの事前のビルドが必要

tsconfig paths の指定
import のパスに別名をつけることができる
{
"compilerOptions": {
"module": "esnext",
"moduleResolution": "bundler",
"paths": {
"@app/*": ["./src/*"]
}
}
}
コンパイル時にパスをそのまま出力してしまうので、以下は問題のあるコードになる
{
"compilerOptions": {
"module": "nodenext",
"paths": {
"node-has-no-idea-what-this-is": ["./oops.ts"]
}
}
}
// TypeScript: ✅
// Node.js: 💥
import {} from "node-has-no-idea-what-this-is";
node_modules を paths で alias をつけるのは禁止。package.json の exports とバッテイングして期待通りの動作にならない可能性があるため。
{
"compilerOptions": {
"paths": {
"pkg": ["./node_modules/pkg/dist/index.d.ts"],
"pkg/*": ["./node_modules/pkg/*"]
}
}
}

tsconfig types の指定
types の指定がある場合は、指定した @types だけが読み込まれる
{
"compilerOptions": {
"types": ["node", "jest", "express"]
}
}

npm の workspace の初期化
非公開で作るとして private を true にしておく
{
"name": "project_name",
"private": true
}
workspace の初期化
$ npm init --scope project_name -w packages/app -w packages/core

npm の workspace のコマンド実行
前提
-workspace
or -w
は workspace を単体で指定する
$ npm run test -workspace packages/app
$ npm run test -w packages/app -w packages/core
-workspaces
or -ws
は workspace を全て指定する
$ npm run test -workspaces
$ npm run test -ws
--if-present
でコマンドが存在する workspace での実行ができる
$ npm run test --workspaces --if-present
install
$ npm install xxx -w packages/app
# package も指定が可能
$ npm install project_name/core -w packages/app
workspace の package は node_modules にシンボリックリンクを作る
./node_modules
├── project_name
│ ├── app -> ../../packages/app
│ └── core -> ../../packages/core
└── typescript

Package のエントリーポイントについて
main
{
"main" : "./src/index.js"
}
と指定した場合 import * from "project_name"
という指定で index.js のモジュールを読み込める
exports
packages/core/src
├── index.js
└── test.js
例えば、上記のファイルがあった時に以下のようにエントリーポイントを複数指定できる。
{
"exports": {
"./*": "./src/*.js"
},
}
つまり、以下のようにインポートが可能になる
import * from "package_name/core/index" // OK
import * from "package_name/core/test" // OK

workspace と tsconfig の設定
前述の内容を踏まえてまずはNG例
NG
paths に node_modules のパスを設定する
paths には node_modules のパスは書いてはいけない
{
"paths": {
"@core/*": ["../../node_modules/package_name/core/dist/*"]
},
}
paths に別パッケージの指定をする
外部依存のパッケージは package.json の exports の指定で読み込むようにする。
別名をつけることで単体で読み込んだ時に動作しなくなるはず。
{
"paths": {
"@core/*": ["../../packages/core/dist/*"]
},
}
ちょっと自信がない
references の設定
references 自体はモジュールを分割してビルド量を減らすための目的であり、モノレポにおいてはこの設定はOKなはず。
また、モノレポでコードを編集する時に references の設定を入れないと IDE でうまくコードの参照を見つけられない。
"references": [{
"path": "../core"
}],

workspace と tsconfig の構成例
間違いあるかもしれませんが、そこまでおかしくないはず。
フォルダ構成
./packages
├── app
│ ├── dist
│ └── src
└── core
├── dist
└── src
Core
{
"name": "project_name/core",
"version": "1.0.0",
"exports": {
"./*": "./dist/*.js"
},
"scripts": {
"build": "tsc -b",
},
}
{
"compilerOptions": {
"composite": true,
"target": "es2016",
"module": "NodeNext",
"declaration": true,
"outDir": "./dist",
"tsBuildInfoFile": "./dist/.tsbuildinfo",
"rootDir": "./src",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"moduleResolution": "NodeNext"
},
"include": ["./src/**/*.ts"]
}
App
{
"name": "project_name/app",
"scripts": {
"build": "tsc -b",
},
}
{
"compilerOptions": {
"composite": true,
"target": "es2016",
"module": "NodeNext",
"declaration": true,
"outDir": "./dist",
"tsBuildInfoFile": "./dist/.tsbuildinfo",
"rootDir": "./src",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"moduleResolution": "NodeNext"
},
"references": [{
"path": "../core"
}],
"include": ["./src/**/*.ts"]
}