知識ゼロから始めるモノレポ開発 (Node.js編)

# きっかけ

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`を設定し、

```json:./package.json
{
  "name": "monorepo",
  "packageManager": "bun@1.0.0",
  "private": true,
  "workspaces": [
    "packages/*",
    "services/*"
  ]
}
```

`./packages/xxx` に使いまわしたいコードや設定ファイル、パッケージ群をnodeのプロジェクトとしておくことで

```json:./packages/tsconfig/package.json
{
  "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` から共通のパッケージとして利用することができるようになります。

```json:./services/awesome-app/package.json
{
  "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` という名前でアクセスできるようになります

```json:./packages/tsconfig/package.json
{
  "name": "@monorepo/tsconfig",
  "private": true,
  "version": "0.0.0",
  "devDependencies": {
    "@tsconfig/next": "^1.0.2",
    "tsconfig-paths": "^4.2.0"
  }
}
```

```json:./packages/tsconfig/tsconfig.json
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "extends": "@tsconfig/next/tsconfig.json",
  "compilerOptions": {
    "allowJs": true
  }
}

```

上記のファイルを`./services/awesome-app/tsconfig.json`で読み込みたい場合は、`devDependencies`に`@monorepo/tsconfig`を記載し、

```json:./services/awesome-app/package.json
{
  "name": "awesome-app",
  "packageManager": "bun@1.0.0",
  "private": true,
  "engines": {
    "node": ">=16.0.0 <=18.x.x"
  },
  "devDependencies": {
    "@monorepo/tsconfig": "workspace:*"
  }
}

```

`extends`で読み込むと良いでしょう。

```json:./services/awesome-app/tsconfig.json
{
  "$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になるかと思います。

```json:./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の設定例

```json:turbo.json
{
  "$schema": "https://turbo.build/schema.json",
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": [".next/**", "!.next/cache/**"]
    },
    "test": {}
  }
}

```

### 実行方法

下記コマンドを実行し、ログがいっぱい流れたら成功です（雑）
ビルド結果がキャッシュされるため、２回目以降の実行が爆速になるのがわかると思います。

```bash
% turbo run test
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3442/ffe48a37-4d5b-adae-e7b4-d9954f18deb4.png)

### 参考
Turborepo でモノレポ構成のプロジェクトを爆速でビルドする | DevelopersIO https://dev.classmethod.jp/articles/turborepo-superfast-monorepo-ci/


# まとめ
流すように説明したので、実際動かしてみたい方は参考資料を見ていただけると幸いです。
車輪の再開発になりそうなjestやstorybook等のパッケージも置いていきたいなー