[Monoepo] Yarn Workspaces

2024-04-12 hit count image

JavaScriptで開発するプロジェクトでモノレポ(Monorepo)を使うための知識である Yarnの Workspaces について紹介します。

概要

このブログポストではYarnWorkspacesを使ってモノレポを構成する方法について紹介します。

ブログシリーズ

このブログはシリーズで作成されました。次のリンクを通じて他のブログポストも確認してください。

Yarn Workspaces

前回のブログポストであるモノレポを使うためのツールで JavaScript パッケージマネージャであるYarnWorkspacesを紹介しました。

今回のブログポストでは実際にYarnWorkspaces機能を使ってモノレポを構成する方法について紹介します。

YarnWorkspacesは前回のブログポストで紹介したSymlinkを使って複数のプロジェクトを単一のコードベースで管理できるようにしてくれる機能です。この機能を使えば簡単にモノレポを構成できます。

例題

Yarnが提供するWorkspace機能を確認するための例題を作成してみましょう。まず、次のようにフォルダとファイル構造を作成します。

.
└── src/
    ├── module-a/
    │   ├── index.js
    │   └── package.json
    └── module-b/
        ├── index.js
        └── package.json

module-apackage.jsonは次のようです。

// src/module-a/package.json
{
  "name": "module-a",
  "version": "1.0.0",
  "main": "index.js"
}

module-bpackage.jsonは次のようです。

// src/module-b/package.json
{
  "name": "module-b",
  "version": "1.0.0",
  "main": "index.js"
}

そして、module-bindex.jsは次のようです。

// src/module-b/index.js
console.log('module-b');

最後にmodule-aindex.jsは次のようです。

// src/module-a/index.js
console.log('module-a');

require('module-b');

このようにファイルを構成した後、次のコマンドを実行してモジュールを正しく読み込めるか確認します。

node src/module-a/index.js

そしたら次のようにエラーが発生することを確認できます。

module-a
node:internal/modules/cjs/loader:1073
  throw err;
  ^

Error: Cannot find module 'module-b'
Require stack:
- /Users/deku/temp/temp/src/module-a/index.js
    at Module._resolveFilename (node:internal/modules/cjs/loader:1070:15)
    at Module._load (node:internal/modules/cjs/loader:923:27)
    at Module.require (node:internal/modules/cjs/loader:1137:19)
    at require (node:internal/modules/helpers:121:18)
    at Object.<anonymous> (/Users/deku/temp/temp/src/module-a/index.js:3:1)
    at Module._compile (node:internal/modules/cjs/loader:1255:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1309:10)
    at Module.load (node:internal/modules/cjs/loader:1113:32)
    at Module._load (node:internal/modules/cjs/loader:960:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:83:12) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [ '/Users/deku/temp/temp/src/module-a/index.js' ]
}

Yarn Workspaces の設定

次はYarnWorkspacesを使ってmodule-amodule-bを使えるようにしてみます。まずルートフォルダ(/)で次のコマンドを使ってYarnWorkspacesを使えるようにします。

yarn init -y

そうするとルートフォルダに次のような内容を含んだpackage.jsonが作成されることを確認できます。

{
  "name": "monorepo",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT"
}

YarnWorkspacesを使うためにはこのpackage.jsonファイルを次のように修正する必要があります。

{
  "name": "monorepo",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "private": true,
  "workspaces": {
    "packages": ["src/module-a", "src/module-b"]
  }
}

モノレポは複数のプロジェクトを持っている単一のコードベースであるため、npmレジストリなどにデプロイする必要はありません。そのためprivatetrueに設定してモノレポがデプロイされないようにします。Yarn V1では必須ですが、Yarn V2からは設定する必要はありません。安全に管理するためにprivatetrueに設定することをお勧めします。もちろん、モノレポ内の個々のプロジェクトはデプロイできるため、それぞれのプロジェクトはprivateを設定する必要はありません。

Workspacesは配列([])またはオブジェクト({})を設定できます。Yarnではオブジェクト形式で作成することを推奨しています。Workspacesの中にpackagesというキーで配列を作成し、それぞれのモジュールを追加しました。このようにそれぞれ指定してもよいですが、次のように*を使って簡単にすべてのモジュールを指定することもできます。

{
  "name": "monorepo",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "private": true,
  "workspaces": {
    "packages": ["src/*"]
  }
}

Yarn Workspaces 確認

これでYarnWorkspacesを使う準備が整いました。次のコマンドを実行してパッケージをインストールします。

yarn install

するとnode_modulesフォルダがルートフォルダに作成され、Symlinkを使ってそれぞれのモジュールが接続されていることを確認できます。

.
├── node_modules
│   ├── module-a -> ../src/module-a
│   └── module-b -> ../src/module-b
├── package.json
├── src
│   ├── module-a
│   │   ├── index.js
│   │   └── package.json
│   └── module-b
│       ├── index.js
│       └── package.json
└── yarn.lock

これでmodule-aからmodule-bを使えるようになりました。次のコマンドを実行してmodule-aが正しく動作するか確認してみましょう。

node src/module-a/index.js

すると次のように問題なくmodule-aが実行されることを確認できます。

module-a
module-b

もちろんSymlinkで接続されているため、module-bのコードを修正するとmodule-aでも修正されたコードを使うことができます。src/module-b/index.jsファイルを開いて次のように修正します。

console.log('module-b!!!');

そして次のコマンドを実行して修正された内容が正しく表示されるか確認してみましょう。

node src/module-a/index.js

すると次のように修正された内容が正しく表示されることを確認できます。

module-a
module-b!!!

.gitignore

Gitでソースコードを管理している場合、.gitignoreファイルを作成して次のように修正してnode_modulesフォルダをGitから除外するようにします。

# .gitignore
node_modules

完了

これでモノレポを使うためYarnWorkspacesを使う方法についてみてみました。YarnWorkspacesは基本的にSymlinkで動作するため、Symlinkについて理解するとよいでしょう。Symlinkについて詳しく知りたい場合は前回のブログポストを参照してください。

皆さんもYarnWorkspacesを使ってモノレポを構成してみてください。

私のブログが役に立ちましたか?下にコメントを残してください。それは私にとって大きな大きな力になります!

アプリ広報

今見てるブログを作成たDekuが開発したアプリを使ってみてください。
Dekuが開発したアプリはFlutterで開発されています。

興味がある方はアプリをダウンロードしてアプリを使ってくれると本当に助かります。

Posts