Skip to main content

[note] Monorepo with Yarn Workspaces

$ yarn add <pkg> -W  # add the dependency to the workspace root

# yarn workspace
$ yarn workspace <workspace_name> add <pkg>
$ yarn workspace <workspace_name> remove <pkg>

# yarn workspace run
$ yarn workspace <workspace_name> start # run start command in the specific workspace
$ yarn workspace <workspace_name> lint # run lint command in the specific workspace

# yarn upgrade
$ yarn upgrade <pkg@version> --scope <@scope>
$ yarn upgrade-interactive

# show workspaces info
$ yarn workspaces info
$ yarn workspaces run test # run the command in each worksapce

Workspaces

workspaces @ yarn

先在 package.json 檔案中:

  • 設定 workspaces 讓 yarn 來處理 packages hoisting
  • 因為 root 的 package 並不是真的會發布到 npm 上的 package,所以需要加上 private: true
+++ package.json
@@ -6,6 +6,7 @@
"license": "MIT",
"devDependencies": {
"husky": "^7.0.4",
+ "lerna": "^4.0.0",
"lint-staged": "^12.1.7",
"prettier": "^2.5.1",
"stylelint": "^14.2.0",
"*.scss": [
"stylelint --fix"
]
+ },
+ "private": true,
+ "workspaces": [
+ "packages/*"
+ ],
}

假設 packages/* 裡包含了 foo 和 bar 兩個資料夾,他們各自是獨立的 package,前者的 package name 是 @pjchender/foo 後者是 @pjchender/bar

.
├── package.json
├── packages
│ ├── bar
│ │ ├── index.js
│ │ └── package.json
│ └── foo
│ ├── index.js
│ └── package.json
└── yarn.lock

當我們執行 yarn 來安裝 dependencies 時,yarn 會在 root 的 node_modules 中幫我們建立 symlink 指稱到對應的 package。可以看到下圖中 root package 的 node_modules 裡會分別建立 symlink 來連到本地 packages/foopackages/bar

.
├── node_modules
│ └── @pjchender
│ ├── bar -> ../../packages/foo
│ └── foo -> ../../packages/bar
├── package.json
├── packages
│ ├── bar
│ │ ├── index.js
│ │ └── package.json
│ └── foo
│ ├── index.js
│ └── package.json
└── yarn.lock

nohoist

workspaces 後除了可以直接使用陣列放入 monorepo 的資料夾外,如果需要更多的設定,也可以改用物件的方式來設定。例如,針對某些套件如果我們不希望被 hoist 的話,可以使用 nohoist 的選項,這時候的設定檔會像這樣:

// package.json
{
"workspaces": {
"packages": [
"packages/*"
],
"nohoist": [
"**/normalize-scss"
]
}
}

這時候 normalize-scss 這個套件就不會被 hoist 在 root,而是會安裝在各 packages 內的 node_modules 中。