npm パッケージが独立して管理されているモノレポ環境に npm workspaces を導入する

2024.06.11

こんにちは、製造ビジネステクノロジー部の若槻です。

npm workspacesを導入することで、モノレポ環境において npm パッケージを効率的に管理することが可能となります。

今回は、npm パッケージが独立して管理されているモノレポ環境に npm workspaces を導入する機会があったので、その手順をまとめてみました。

手順

導入前の環境

backendおよびfrontendの 2 つの各サブリポジトリで npm パッケージが独立して管理されており、package-lock.jsonおよびnode_modulesがそれぞれ存在しているという環境です。

$ tree -L 3          
.
└── packages
    ├── backend
    │   ├── index.js
    │   ├── node_modules
    │   ├── package-lock.json
    │   └── package.json
    └── frontend
        ├── index.js
        ├── node_modules
        ├── package-lock.json
        └── package.json

5 directories, 6 files

backendにはdayjsfrontendにはuuidがインストールされています。

$ npm ls --prefix packages/backend
backend@1.0.0 /Users/wakatsuki.ryuta/projects/local/20240611-npm-workspaces/packages/backend
└── dayjs@1.11.11

$ npm ls --prefix packages/frontend
frontend@1.0.0 /Users/wakatsuki.ryuta/projects/local/20240611-npm-workspaces/packages/frontend
└── uuid@10.0.0

それぞれのサブリポジトリに対してnpm testを実行すると、backendではdayjsfrontendではuuidを利用した処理の結果が出力されます。

$ npm run test --prefix packages/backend 

> backend@1.0.0 test
> node index.js

2024-06-11

$ npm run test --prefix packages/frontend

> frontend@1.0.0 test
> node index.js

1a004895-4a40-444a-84d4-77ef77fd52a2

npm workspaces を導入する

サブリポジトリの package-lock.json および node_modules を削除

npm workspaces では node_modules および package-lock.json はルートディレクトリで集約して管理されるため、サブリポジトリからは削除します。

rm -fr packages/backend/node_modules
rm -fr packages/backend/package-lock.json
rm -fr packages/frontend/node_modules
rm -fr packages/frontend/package-lock.json

ルートディレクトリで npm workspaces を初期化

npm initコマンドをルートディレクトリに対して実行します。

npm init -y

これによりルートにpackage.jsonが作成されます。

サブリポジトリをワークスペースとして追加

さらに npm init コマンドを -w オプションとともに実行して、backendディレクトリをワークスペースとして追加します。

npm init -w packages/backend -y

これにより、ルートのpackage.jsonworkspacesフィールドが追加され、backendディレクトリがワークスペースとして追加されます。また、backendディレクトリのpackage.jsonにも項目がいくつか追加されます。またルートディレクトリにpackage-lock.jsonおよびnode_modulesが追加されます。

$ git diff
diff --git a/package.json b/package.json
index fef7b40..26572e6 100644
--- a/package.json
+++ b/package.json
@@ -8,5 +8,8 @@
   "keywords": [],
   "author": "",
   "license": "ISC",
-  "description": ""
+  "description": "",
+  "workspaces": [
+    "packages/backend"
+  ]
 }
diff --git a/packages/backend/package.json b/packages/backend/package.json
index 7fc1bfc..ba839e1 100644
--- a/packages/backend/package.json
+++ b/packages/backend/package.json
@@ -8,5 +8,9 @@
   },
   "dependencies": {
     "dayjs": "1.11.11"
-  }
+  },
+  "keywords": [],
+  "author": "",
+  "license": "ISC",
+  "description": ""
 }

同様にfrontendディレクトリもワークスペースとして追加します。

$ npm init -w packages/frontend -y

こちらもルートのpackage.jsonにワークスペースとしてfrontendディレクトリが追加され、frontendディレクトリのpackage.jsonにも項目がいくつか追加されます。また package-lock.json も更新されます。

$ git diff
diff --git a/package-lock.json b/package-lock.json
index 080cb52..c6f0fa2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,7 +9,8 @@
       "version": "1.0.0",
       "license": "ISC",
       "workspaces": [
-        "packages/backend"
+        "packages/backend",
+        "packages/frontend"
       ]
     },
     "node_modules/backend": {
@@ -22,12 +23,37 @@
       "integrity": "sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==",
       "license": "MIT"
     },
+    "node_modules/frontend": {
+      "resolved": "packages/frontend",
+      "link": true
+    },
+    "node_modules/uuid": {
+      "version": "10.0.0",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz",
+      "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==",
+      "funding": [
+        "https://github.com/sponsors/broofa",
+        "https://github.com/sponsors/ctavan"
+      ],
+      "license": "MIT",
+      "bin": {
+        "uuid": "dist/bin/uuid"
+      }
+    },
     "packages/backend": {
       "version": "1.0.0",
       "license": "ISC",
       "dependencies": {
         "dayjs": "1.11.11"
       }
+    },
+    "packages/frontend": {
+      "version": "1.0.0",
+      "license": "ISC",
+      "dependencies": {
+        "uuid": "10.0.0"
+      },
+      "devDependencies": {}
     }
   }
 }
diff --git a/package.json b/package.json
index 26572e6..e7d4076 100644
--- a/package.json
+++ b/package.json
@@ -10,6 +10,7 @@
   "license": "ISC",
   "description": "",
   "workspaces": [
-    "packages/backend"
+    "packages/backend",
+    "packages/frontend"
   ]
 }
diff --git a/packages/frontend/package.json b/packages/frontend/package.json
index d778e19..3bcd2a1 100644
--- a/packages/frontend/package.json
+++ b/packages/frontend/package.json
@@ -8,5 +8,10 @@
   },
   "dependencies": {
     "uuid": "10.0.0"
-  }
+  },
+  "devDependencies": {},
+  "keywords": [],
+  "author": "",
+  "license": "ISC",
+  "description": ""
 }

導入後の環境

npm workspaces を導入した後は、npm パッケージが集約して管理されるようになります。

$ npm ls
20240611-npm-workspaces@1.0.0 /Users/wakatsuki.ryuta/projects/local/20240611-npm-workspaces
├─┬ backend@1.0.0 -> ./packages/backend
│ └── dayjs@1.11.11
└─┬ frontend@1.0.0 -> ./packages/frontend
  └── uuid@10.0.0

もちろん各ワークスペースに対してそれぞれのパッケージがインストールされているため、パッケージを利用する処理も問題なく事項できます。

$ npm run test -w backend

> backend@1.0.0 test
> node index.js

2024-06-11

$  npm run test -w frontend

> frontend@1.0.0 test
> node index.js

fe5c4306-089b-4b2c-8056-d344e778271c

おわりに

npm パッケージが独立して管理されているモノレポ環境に npm workspaces を導入する方法をご紹介しました。

いちから npm 環境を作り直す必要が無いのが良いですね。

以上