📦
備忘録: npm workspace によるモノレポ設定 と sharedパッケージ
0. ディレクトリ構造
記事内では、以下のディレクトリ構造を想定しています。
project-root
├─ packages
│ ├─ frontend
│ │ ├─ package.json
│ │ └─ tsconfig.json
│ ├─ backend
│ │ ├─ package.json
│ │ └─ tsconfig.json
│ └─ shared
│ ├─ package.json
│ └─ tsconfig.json
└─ package.json
1. プロジェクトルートの初期化
ルート直下の package.json で workspaces を定義し、プロジェクト全体の依存関係を管理します。
- コマンド
cd [your-root-dir]
npm init
- package.json (ルートディレクトリ)
{
"name": "your-app-name",
// ...
"workspaces": [
"packages/*"
],
// ...
}
※ packages以外のディレクトリ名でも可
パッケージがネストしている場合、こうなります
"workspaces": [
"packages/*/*"
]
2. 各パッケージの作成
一例として、frontend, backend, shared の3つを作成します。
- コマンド
cd [path-to-target-package]
# 例: cd ./packages/shared
npm初期化
npm init
3. 参照されるパッケージの設定(ここではsharedのこと)
- package.json (sharedディレクトリ)
{
"name": "@pkg/shared",
"version": "0.0.1"
"main": "./dist/index.js", // ビルド成果物のエントリーポイント
"types": "./src/index.ts", // コーディング時のエントリーポイント
// ...
}
4. 依存関係の定義
frontend や backend の package.json で、shared を依存先に指定します。
- package.json (依存する側の各パッケージ)
{
"dependencies": {
"@pkg/shared": "*" // sharedをパッケージとして利用する
}
}
- コマンド (プロジェクトルート)
npm install
# これによって、@pkg/shared がインストールされる
5. tsc初期化
- コマンド (各パッケージ)
npm install typescript
npx tsc init
#または
npx tsc --init
6. tsconfigを編集設定
- tsconfig.json (shared)
{
"compilerOptions": {
"outDir": "dist",
"rootDir": "src",
"composite": true, // "declaration": true を設定する際に必要になることがある
"declaration": true, // .d.ts を出力する場合trueにする
// ...
},
"include": ["src"]
}
各項目の意図
| "outDir" | ビルド成果物の出力先 |
| "rootDir" | ソースディレクトリ |
| "include" | tscがコンパイルするファイルを指定 |
- tsconfig.json (FE/BE)
{
"compilerOptions": {
"paths": {
"@pkg/shared": ["<path-to-shared>/src/index.ts"]
// 例: ../shared/src/index.ts
// ↑これがないとtscがパス解決できません
}
},
"references": [
{ "path": "../shared/" }
]
}
7. npmコマンド例
- package.json (プロジェクトルート)
{
// ...
"scripts": {
"syncDb": "npm run syncDb -w packages/backend",
"build:shared": "npm run build -w packages/shared",
"build:frontend": "npm run build -w packages/frontend",
"build:backend": "npm run build -w packages/backend",
"start:backend": "npm run start -w packages/backend",
"dev:frontend": "npm run dev -w packages/frontend",
// ...
"tsc:frontend": "npm run tsc -w packages/frontend",
"tsc:backend": "npm run tsc -w packages/backend"
},
- コマンドを使用
$project-root> npm run tsc:frontend
# → "npm run tsc -w packages/frontend" を呼び出し
# → frontendの "npm run tsc" が実行される
:. npx tsc -b --noemit
※ 実行されているのは以下の部分です。
// packages/frontend/package.json より抜粋
{
"scripts": {
"tsc": "npx tsc -b --noemit"
}
}
想定されるエラーと対処法
エラー
tsconfig.json
ファイル 'c:/project-root/app/packages/backend/index.ts' が 'rootDir' 'c:/project-root/packages/backend/src' の下にありません。'rootDir' にすべてにソース ファイルが含まれている必要があります。
ファイルがプログラム内に存在します。理由:
既定で一致するインクルード パターン '**/*'
'c:/Users/Fujishu/Desktop/Document/portfolios/ai/sdd-tutorial-todo-app/packages/backend/package.json' には値 "module" のフィールド "type" があるため、ファイルは ECMAScript モジュールです。
対処
このエラーは、src内にすべてのソースコードが収まっていないということを意味しています。
- tsconfig
最初に疑うのは tsconfig の設定ミスです。
依存元と依存先の両方に設定漏れがないかを確認します。
一番疑わしいものとして、依存関係の指定ミスがあります。
tsconfig.json
{
"compilerOptions": {
// ...
"paths": {
"@pkg/shared": ["../shared/src/index.ts"]
},
},
// ↓references を追加する
"references": [
{ "path": "../shared/" }
]
}
"paths: {...}"はパス解決をしてくれますが、「依存パッケージだからsrcには入っていない」 ということを伝えない限りエラーは消えません。
そこで、"references"を合わせて使うことで、sharedを外部パッケージとして認識させることができます。
- ディレクトリ構造
それでも一切問題が見つからない場合、ディレクトリ構成がおかしい可能性を疑います。
実際、私はディレクトリ構造を間違えてこのエラーが発生しました。
# 求める構造
backend
- src
- index.ts
# 今回の設定にそぐわない構造
backend
- index.ts
Discussion