ということをやりたくて、こうやったらできたという覚書。
やりたいこと
こういうモノレポ構成とする。
- package.json
- package-lock.json
- packages
- shared
- app1
- app2
で、app1
にあるコードベースを@myapp/app1
とした場合、@myapp/shared
に置いたTSファイルを、そのままモジュールとして利用したいとする。
import { foo } from "@myapp/shared";
import { bar } from "@myapp/shared/bar";
// This is @myapp/app1 or @myapp/app2 code
@myapp/app1
と@myapp/app2
は、それぞれ独自のコードベースになってて、それぞれtsc
ではなくvite
やesbuild
などのバンドラーを使う前提。
共通モジュール側
package.json
の抜粋。
{
"name": "@myapp/shared",
"version": "1.0.0",
"type": "module",
"exports": {
".": "./src/index.ts",
"./bar": "./src/foo.ts"
},
}
exports
はmain
でもいいけど、こうしておくと後からネームスペースが切れるので便利。type: module
はお好みで。
正直、特別な指定というものはない。
モジュール利用側
兎にも角にも、npm i @myapp/shared -w @myapp/app1
でインストールする。(npm
、どこかのバージョンから、モノレポのルートじゃなくても、その個別パッケージ内でnpm i
したらいい感じに処理してくれるようになった?)
{
"name": "@myapp/app1",
"version": "1.0.0",
"type": "module",
"dependencies": {
"@myapp/shared": "^1.0.0"
}
}
あとはこのtsconfig.json
の抜粋。
{
"compilerOptions": {
"module": "esnext",
"moduleResolution": "bundler"
}
}
このmoduleResolution: bundler
がすべてをいい感じに解決してくれる。
TypeScript: TSConfig Reference - Docs on every TSConfig option https://www.typescriptlang.org/tsconfig#moduleResolution
まとめ
モノレポ構成なおかげでnode_modules
はサクッと解決できるし、こういうのが本当にカジュアルにできちゃう時代になったんだなあ。