pnpmでモノレポの初期設定を行うには?
techはじめに
この記事ではpnpm workspaceを使用したモノリポジトリの初期設定方法について記録します。
フロントエンドのみのアプリケーション開発から、バックエンド,Web & CLI開発に進む開発者にオススメです。
アプリケーション構成として、Webアプリケーション・CLI・バックエンド...など動作環境・場所が異なるパッケージを単一リポジトリで管理することができます。
モノレポを採用する大きな利点として以下の2点がわかりやすいです。
- レポジトリ管理の煩雑さを軽減する
- READMEなどドキュメントに差異が発生するのを防ぐ
今回私は、Webアプリ・ローカルCLI・バックエンドの3環境構成を実装するためにモノレポ構成を使用することにしました。
そんなわけで、本記事ではpnpmにてモノレポを一から構築する方法を解説していきます。
構築方法
基本のディレクトリ構成
以下のようにリポジトリを作成します。
root/
├── pnpm-workspace.yaml ← ワークスペース定義
├── package.json ← ルートのpackage.json
├── tsconfig.base.json ← 共通設定のtsconfig.json
├── apps/
│ ├── web/ ← フロントエンド等
│ └── cli/ ← CLIツール等
│ └── tsconfig.json ← 個別設定のtsconfig.json
└── packages/
├── ui/ ← 共有UIコンポーネント
├── config/ ← 共有設定(eslint, tsconfig等)
└── utils/ ← 共有ユーティリティ
今回は、CLIをnpmパッケージとして配布するためapps,packagesを採用していますが、自分の判別しやすい名称であれば何でも構いません。
ただし、アプリなのか、ライブラリなのかを判別しやすい名称にしておくことがオススメです。
pnpm-workspace.yamlに設定を記述する
どのディレクトリにパッケージが配置されるかを定義します。
packages:
- "apps/*"
- "packages/*"
package.jsonに設定を記述する
{
"private": true, // 原則true,npmパッケージとして公開したいものにだけfalseを設定する。デフォルト値はfalse
"scripts": {
"build": "pnpm -r build", // -r はrecursiveのこと。サブディレクトリまで再帰的にbuildされる
"dev": "pnpm --filter @apps/web dev" // どこからでもwebアプリのみローカルホストで起動する。なくても可
}
}
tsconfig.jsonを作成する
プロジェクトルートにはtsconfig.base.json
個別パッケージにはtsconfig.jsonを配置する
tsconfig.base.json
{
// Visit https://aka.ms/tsconfig to read more about this file
"compilerOptions": {
"module": "nodenext",
"target": "esnext",
"types": [],
"esModuleInterop": true,
// Other Outputs
"sourceMap": true,
"declaration": true,
"declarationMap": true,
// Stricter Typechecking Options
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
// Recommended Options
"strict": true,
"verbatimModuleSyntax": true,
"isolatedModules": true,
"noUncheckedSideEffectImports": true,
"moduleDetection": "force",
"skipLibCheck": true
}
}
tsconfig.json
{
// Visit https://aka.ms/tsconfig to read more about this file
"extends": "../../tsconfig.base.json",
"compilerOptions": {
// File Layout
"rootDir": "./src",
"outDir": "./dist",
// Environment Settings
// See also https://aka.ms/tsconfig/module
"module": "nodenext",
"target": "esnext",
"types": [],
// For nodejs:
// "lib": ["esnext"],
// "types": ["node"],
// and npm install -D @types/node
// Other Outputs
"sourceMap": true,
"declaration": true,
"declarationMap": true,
// Stricter Typechecking Options
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
// Recommended Options
"strict": true,
"jsx": "react-jsx",
"verbatimModuleSyntax": true,
"isolatedModules": true,
"noUncheckedSideEffectImports": true,
"moduleDetection": "force",
"skipLibCheck": true
},
"include": ["**/*.ts"],
"exclude": ["node_modules"]
}
Next.jsのtsconfig.json
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"target": "ES2017"
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
".next/dev/types/**/*.ts",
"**/*.mts"
],
"exclude": ["node_modules"]
}
Tips
パッケージ間の依存設定
例:もし、apps/webからpackages/utilsを使用する場合
// apps/web/package.json
{
"dependencies": {
"@myapp/utils": "workspace:*"
}
}
workspace:*と書けばローカルのものを参照します。書かない場合、npmレジストリを探しに行くので注意です。
よく使うコマンド
| コマンド | 意味 |
|---|---|
pnpm install | package.jsonに書かれた全パッケージ一括インストール |
pnpm -r build | 全パッケージでbuild実行 |
pnpm --filter @apps/web dev | 特定パッケージのみ実行 |
pnpm add lodash --filter @apps/web | 特定パッケージに依存(ライブラリ・モジュール)追加 |
※ 原則、ライブラリ・依存管理はパッケージごとに行います。
.gitignoreの扱い
パッケージごとにpnpm create next-appなど初期化コマンドを走らせた場合、.gitignoreが作成されることがあります。
その場合の選択肢としては2つ
- ルートの.gitignoreにマージする ルートで一元管理できます
- そのまま残す そのまま残しておいても実害はありません。gitが両方を適用してくれるので問題ないです。 パッケージ毎に追加の無視ルールを設定できるという利点もあります。
.gitignoreはgithubがテンプレートを用意してくれているので活用しましょう。 Node.jsの場合は、Node.gitignoreがおすすめです。
複数環境への挑戦
ということで現在、そして今後作っていくであろう複数環境をまたぐアプリケーションのためのモノレポジトリ構成についてまとめてみました。
フロントエンド・バックエンド両方を組み込んだり、CLIを作ってみたり...とモノレポを活用してみてください!
