きっかけ
next.jsのアプリケーションをモノレポでやりたいというオーダーがあったが何から手をつければ… いう状態から調べたことを書き散らしていきます。
方針
- モノレポ管理するツールの導入
- workspacesで共通パッケージを使いたい
- tsconfig, linter等のconfigをある程度共通化したい
- UIコンポーネント等の密結合な実装はなし
モノレポ管理するツールの導入
今回は、共通のUIを実装する等の密結合な要望はなく、Next.jsアプリとAPIサーバを同じリポジトリに置いて管理したいというオーダだったため、Bun workspaces
, Turborepo
を採用することにしました。
Nxは高機能でモノリシックなシステム構築にフォーカスを置いており、コンポーネントの共通化等を行う予定は今回ないので、Turborepo
を採用しました。
参考
Nx と Turborepo の比較 https://zenn.dev/okmttdhr/articles/a919bb29d9d5c9#nx-%E3%81%A8-turborepo-%E3%81%AE%E6%AF%94%E8%BC%83
Bun
Bunとは、JavaScriptランタイムで高速で動作するnpm, yarnのようなパッケージ管理機能を有しています。
パッケージのインストールや動作も速く、安定していてBun特有の地雷も特に見受けられない。
v1.0が出ているので使っていきます。
参考
Bun1.0がもうすぐリリースされるぞ! https://zenn.dev/dojineko/articles/bun-1-coming-soon
Bun workspaces
npmと同様にBunでもworkspaceの機能が搭載されています。
workspaceとは、パッケージをお互い参照できる形で管理でき、node_modules
をシェアすることで依存関係も共通化できるものと思っておけば良いと思います。
ルートのpackage.json
にworkspaces
を設定し、
{
"name": "monorepo",
"packageManager": "bun@1.0.0",
"private": true,
"workspaces": [
"packages/*",
"services/*"
]
}
./packages/xxx
に使いまわしたいコードや設定ファイル、パッケージ群をnodeのプロジェクトとしておくことで
{
"name": "@monorepo/tsconfig",
"private": true,
"version": "0.0.0",
"devDependencies": {
"@tsconfig/next": "^1.0.2",
"@tsconfig/node-lts": "^18.12.5",
"tsconfig-paths": "^4.2.0"
}
}
./services/awesome-app
から共通のパッケージとして利用することができるようになります。
{
"name": "awesome-app",
"packageManager": "bun@1.0.0",
"private": true,
"devDependencies": {
"@monorepo/eslint-config": "workspace:*",
"@monorepo/jest-config": "workspace:*",
"@monorepo/tsconfig": "workspace:*"
}
}
workspaceでtsconfigを共通化
例として、./packages/tsconfig
にtsconfigに関連するファイルを設置していきます
乱暴に説明すると、
./packages/tsconfig/
に下記のファイルを用意することで@monorepo/tsconfig/tsconfig.json
という名前でアクセスできるようになります
{
"name": "@monorepo/tsconfig",
"private": true,
"version": "0.0.0",
"devDependencies": {
"@tsconfig/next": "^1.0.2",
"tsconfig-paths": "^4.2.0"
}
}
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@tsconfig/next/tsconfig.json",
"compilerOptions": {
"allowJs": true
}
}
上記のファイルを./services/awesome-app/tsconfig.json
で読み込みたい場合は、devDependencies
に@monorepo/tsconfig
を記載し、
{
"name": "awesome-app",
"packageManager": "bun@1.0.0",
"private": true,
"engines": {
"node": ">=16.0.0 <=18.x.x"
},
"devDependencies": {
"@monorepo/tsconfig": "workspace:*"
}
}
extends
で読み込むと良いでしょう。
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@monorepo/tsconfig/tsconfig.json",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./*"]
}
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.mts",
"**/*.tsx",
"**/*.js",
"**/*.mjs",
".next/types/**/*.ts"
],
"exclude": ["node_modules"]
}
eslint等も同様にいけるので興味があれば、参考を追っていただけると!
参考
Bun workspace で始めるモノレポ生活 https://azukiazusa.dev/blog/bun-workspace/
monorepo (yarn workspace) で tsconfig や .eslintrc をいい感じに管理する https://zenn.dev/shinnoki/articles/3f008f53b2312f
Turborepo
workspaces配下のpackage.jsonをもとに、一括でテストやビルドを実行することができ、キャッシュもしてくれます。
turborepoをインストールして、% bun run test
を実行するとなるとこんな感じのpackage.jsonになるかと思います。
{
"name": "monorepo",
"packageManager": "bun@1.0.0",
"private": true,
"engines": {
"node": ">=16.0.0 <=18.x.x"
},
"workspaces": [
"packages/*",
"services/*"
],
"scripts": {
"build": "turbo run build",
"test": "turbo run test",
},
"devDependencies": {
"turbo": "^1.11.1"
}
}
Turborepoの設定例
{
"$schema": "https://turbo.build/schema.json",
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "!.next/cache/**"]
},
"test": {}
}
}
実行方法
下記コマンドを実行し、ログがいっぱい流れたら成功です(雑)
ビルド結果がキャッシュされるため、2回目以降の実行が爆速になるのがわかると思います。
% turbo run test
参考
Turborepo でモノレポ構成のプロジェクトを爆速でビルドする | DevelopersIO https://dev.classmethod.jp/articles/turborepo-superfast-monorepo-ci/
まとめ
流すように説明したので、実際動かしてみたい方は参考資料を見ていただけると幸いです。
車輪の再開発になりそうなjestやstorybook等のパッケージも置いていきたいなー