【Node.js】lernaとnpmのworkspacesでMonorepoな環境を構築する
Node.jsでlernaとnpmのworkspacesを使ってMonorepoな環境を構築したい!
概要
今回の記事では、Node.jsでlernaとnpmのworkspacesを使ってMonorepoな環境を構築する手順を掲載する。
Monorepoとは、複数のプロジェクトを単一のリポジトリで管理する方法。共通の処理があったり、複数のアプリを合わせて、1つのサービスとするような感じのプロジェクト郡の管理に便利だったり。
lernaはバージョン管理やパッケージの公開に強い。以前は、Monorepoなパッケージ管理機能を持ってたんだけども。後述するnpmのworkspacesなどの登場でそれらを使うことを推奨してて現在のバージョンでは関連するコマンドが使えなくなってる。ちなみにReactやJestにも採用されてるらしい。
npmのworkspacesではMonorepoなパッケージ管理機能(共通の外部パッケージの効率的な管理や管理してるプロジェクト同士の依存関係の解決など)やプロジェクト管理を行うことができる。
仕様書
環境
- Node.js 20.15.0
- npm 10.8.1
- lerna 8.1.8
手順書
lerna
のプロジェクトを作るディレクトリーの中でlerna
をインストールする。
npm install -d lerna
lerna
でプロジェクトを初期化する。
npx lerna init
my_workspace
がプロジェクトだとして下記のような感じでディレクトリーとファイルが作られる。
my_workspace
node_module
.gitgnore
lerna.json
package-lock.json
package.json
lerna.json
の中身を確認する。
{
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
"version": "0.0.0",
"packages": [
"packages/*"
]
}
packages
のpackages/*
がlerna
で管理するプロジェクトの保管場所になるのでディレクトリーpackages
を作って、この中にプロジェクトを作ったり、移動したりする。
package.json
にもworkspaces
を追加する。書き方はlerna.json
と同じ感じ。
{
"name": "my_workspace"
"private": true,
"workspaces": [
"packages/*"
],
"description": ""
}
公開する予定もないので"private": true
も追記しておく。
管理してるプロジェクト同士の依存関係の簡単な設定の例
構成がこんな感じになってるとして
my_workspace
packages
main_app
admin_app
main_app
とadmin_app
があって、admin_app
がmain_app
に依存してるとする場合、はadmin_app
のpackage.json
のdependencies
の中に"main_app": "^1.0.0"
を追加する。
{
"name": "admin_app",
"version": "1.0.0",
"private": true,
...
"dependencies": {
...
"main_app": "*"
},
...
}
もしくはコマンドを使う。
npm install main_app --workspace=admin_app
admin_app
からmain_app/src/share/my_compornent.tsx
とmain_app/src/share/logo.png
をインポートする例。
main_app
src
share
index.ts
logo.png
MyCompornent.tsx
main_app/src/share/MyCompornent.tsx
がこんな感じになってるとする。
const MyCompornent = () => {
return (<h1>MyCompornent</h1>);
};
export default MyCompornent;
main_app/src/share/index.ts
がエクスポートに使うファイルになる。
export * from './MyCompornent';
import logo from './logo.png';
export const Logo = logo;
export { default as MyCompornent } from './MyCompornent';
main_app/package.json
にexports
を設定する。
{
"name": "main_app",
...
"exports": {
"./share": "./src/share/index.ts",
},
...
}
インポートする側admin_app
では下記のような感じで使えるようになる。
import { MyCompornent, Logo } from 'main_app/share';
トラブルシューティング
lerna
でプロジェクトを初期化する際に下記のようなエラーが発生する場合
npx lerna init
lerna ERR! Cannot initialize lerna because your package manager has not been configured to use `workspaces`, and you have not explicitly specified any packages to operate on
lerna ERR! See https://lerna.js.org/docs/getting-started#adding-lerna-to-an-existing-repo for how to resolve this
既に作成されたプロジェクトを含んでる状態で初期化しようとすると発生することがある。その場合は、管理したいプロジェクトがあるディレクトリーをオプションで指定して初期化する。
ディレクトリーがひとつの場合。
npx lerna init --packages="packages/*"
ディレクトリーが複数ある場合。
npx lerna init --packages="packages1/*" --packages="packages2/*"
まとめ(感想文)
メインのアプリがあって、管理アプリなどを別のプロジェクトで作る場合や共通のコードがある場合に使えるかもね!
参考文献・引用
下記の記事を参考にさせて頂きました。ありがとうございました。