如何在 Monorepo 中運行多個開發包 (How to run multiple packages in development inside a Monorepo)


問題描述

如何在 Monorepo 中運行多個開發包 (How to run multiple packages in development inside a Monorepo)

我有一個 monorepo,它使用 lerna 和 yarn 工作區用於前端應用程序和庫。我在根 package.json 中添加了一系列 npm 腳本,以管理每個包(應用程序、lib、插件),就像本文末尾的代碼一樣。問題是我的根 package.json 變得很大,而我才剛剛開始。另一個問題是,如果我需要在 CRM 中開發一個使用 i18n lib 的組件庫中使用的組件,我需要在 3 個單獨的終端窗口中啟動 3 個包,並且我有可能同時開發更多依賴包。

我認為將 start:crm 例如放在安裝在 CRM 中的每個包中(使用 ‑‑parallel),我認為這不是一個好主意。


參考解法

方法 1:

Appropriate tooling is a must here.

I had similar problem: Yarn workspaces with tens of packages depending on each other deeply. And my package.json looked like this:

{
  "scripts": {
    "all": "run‑s \"generic all\" \"all:apps all\" ‑‑",
    "all:apps": "run‑p ‑‑aggregate‑output \"eslint‑config {@}\" \"apps1 {@}\" \"apps2 {@}\" ‑‑",
    "apps1": "run‑s \"apps1:deps {@}\" \"apps1:c {@}\" ‑‑",
    "apps1:c": "run‑p ‑‑aggregate‑output \"hatsy:c {@}\" ‑‑",
    "apps1:deps": "run‑s \"route‑match:c {@}\" ‑‑",
    "apps2": "run‑p ‑‑aggregate‑output \"siteparts:c {@}\" \"realworld‑app:c {@}\" \"examples:c {@}\" ‑‑",
    "build": "run‑s \"generic build {@}\" \"all:apps build {@}\" ‑‑",
    "lint": "run‑p ‑‑aggregate‑output \"generic lint {@}\" \"all:apps lint {@}\" ‑‑",
    "test": "run‑p ‑‑aggregate‑output \"generic test {@}\" \"test:apps test {@}\" ‑‑",
    "test:apps": "run‑p ‑‑aggregate‑output \"apps1:deps {@}\" \"apps1:c {@}\" \"siteparts:c {@}\" \"realworld‑app:c {@}\" ‑‑",
    "a‑iterable": "run‑s \"call‑thru {@}\" \"a‑iterable:c {@}\" ‑‑",
    "a‑iterable:c": "run‑s ‑l \"a‑iterable:x {@}\" ‑‑",
    "a‑iterable:x": "yarn workspace @proc7ts/a‑iterable",
    "call‑thru": "run‑s \"primitives:c {@}\" \"call‑thru:c {@}\" ‑‑",
    "call‑thru:c": "run‑s ‑l \"call‑thru:x {@}\" ‑‑",
    "call‑thru:x": "yarn workspace @proc7ts/call‑thru",
    "context‑values": "run‑s \"call‑thru {@}\" \"context‑values:deps {@}\" \"context‑values:c {@}\" ‑‑",
    "context‑values:c": "run‑s ‑l \"context‑values:x {@}\" ‑‑",
    "context‑values:deps": "run‑p ‑‑aggregate‑output \"a‑iterable:c {@}\" \"fun‑events:c {@}\" ‑‑",
    "context‑values:x": "yarn workspace @proc7ts/context‑values",
    "delta‑set": "run‑s \"delta‑set:c {@}\" ‑‑",
    "delta‑set:c": "run‑s ‑l \"delta‑set:x {@}\" ‑‑",
    "delta‑set:x": "yarn workspace @proc7ts/delta‑set",
    "eslint‑config": "run‑s \"eslint‑config:c {@}\" ‑‑",
    "eslint‑config:c": "run‑s ‑l \"eslint‑config:x {@}\" ‑‑",
    "eslint‑config:x": "yarn workspace @proc7ts/eslint‑config",
    "fun‑events": "run‑s \"call‑thru {@}\" \"fun‑events:c {@}\" ‑‑",
    "fun‑events:c": "run‑s ‑l \"fun‑events:x {@}\" ‑‑",
    "fun‑events:x": "yarn workspace @proc7ts/fun‑events",
    "hatsy": "run‑s \"hatsy:deps {@}\" \"hatsy:c {@}\" ‑‑",
    "hatsy:c": "run‑s ‑l \"hatsy:x {@}\" ‑‑",
    "hatsy:deps": "run‑p ‑‑aggregate‑output \"route‑match {@}\" \"http‑header‑value:c {@}\" ‑‑",
    "hatsy:x": "yarn workspace @hatsy/hatsy",
    "http‑header‑value": "run‑s \"http‑header‑value:c {@}\" ‑‑",
    "http‑header‑value:c": "run‑s ‑l \"http‑header‑value:x {@}\" ‑‑",
    "http‑header‑value:x": "yarn workspace @hatsy/http‑header‑value",
    "route‑match": "run‑s \"primitives:c {@}\" \"route‑match:c {@}\" ‑‑",
    "route‑match:c": "run‑s ‑l \"route‑match:x {@}\" ‑‑",
    "route‑match:x": "yarn workspace @hatsy/route‑match",
    "input‑aspects": "run‑s \"input‑aspects:deps0 {@}\" \"input‑aspects:deps1 {@}\" \"input‑aspects:c {@}\" ‑‑",
    "input‑aspects:c": "run‑s ‑l \"input‑aspects:x {@}\" ‑‑",
    "input‑aspects:deps0": "run‑p ‑‑aggregate‑output \"call‑thru {@}\" \"namespace‑aliaser:c {@}\" \"render‑scheduler:c {@}\" ‑‑",
    "input‑aspects:deps1": "run‑p ‑‑aggregate‑output \"a‑iterable:c {@}\" \"fun‑events:c {@}\" \"delta‑set:c {@}\" ‑‑",
    "input‑aspects:x": "yarn workspace @proc7ts/input‑aspects",
    "namespace‑aliaser": "run‑s \"namespace‑aliaser:c {@}\" ‑‑",
    "namespace‑aliaser:c": "run‑s ‑l \"namespace‑aliaser:x {@}\" ‑‑",
    "namespace‑aliaser:x": "yarn workspace @proc7ts/namespace‑aliaser",
    "primitives": "run‑s \"primitives:c {@}\" ‑‑",
    "primitives:c": "run‑s ‑l \"primitives:x {@}\" ‑‑",
    "primitives:x": "yarn workspace @proc7ts/primitives",
    "render‑scheduler": "run‑s \"render‑scheduler:c {@}\" ‑‑",
    "render‑scheduler:c": "run‑s ‑l \"render‑scheduler:x {@}\" ‑‑",
    "render‑scheduler:x": "yarn workspace @proc7ts/render‑scheduler",
    "style‑producer": "run‑s \"style‑producer:deps0 {@}\" \"style‑producer:deps1 {@}\" \"style‑producer:c {@}\" ‑‑",
    "style‑producer:c": "run‑s ‑l \"style‑producer:x {@}\" ‑‑",
    "style‑producer:deps0": "run‑p ‑‑aggregate‑output \"call‑thru {@}\" \"namespace‑aliaser:c {@}\" \"render‑scheduler:c {@}\" ‑‑",
    "style‑producer:deps1": "run‑p ‑‑aggregate‑output \"a‑iterable:c {@}\" \"fun‑events:c {@}\" ‑‑",
    "style‑producer:x": "yarn workspace @proc7ts/style‑producer",
    "examples": "run‑s \"generic {@}\" \"examples:c {@}\" ‑‑",
    "examples:c": "run‑s ‑l \"examples:x {@}\" ‑‑",
    "examples:x": "yarn workspace @wesib/examples",
    "generic": "run‑s \"wesib {@}\" \"generic:deps {@}\" \"generic:c {@}\" ‑‑",
    "generic:c": "run‑s ‑l \"generic:x {@}\" ‑‑",
    "generic:x": "yarn workspace @wesib/generic",
    "generic:deps": "run‑p ‑‑aggregate‑output \"http‑header‑value:c {@}\" \"input‑aspects:c {@}\" \"style‑producer:c {@}\" ‑‑",
    "realworld‑app": "run‑s \"generic {@}\" \"realworld‑app:c {@}\" ‑‑",
    "realworld‑app:c": "run‑s ‑l \"realworld‑app:x {@}\" ‑‑",
    "realworld‑app:x": "yarn workspace @wesib/realworld‑app",
    "wesib": "run‑s \"wesib:deps {@}\" \"wesib:c {@}\" ‑‑",
    "wesib:c": "run‑s ‑l \"wesib:x {@}\" ‑‑",
    "wesib:x": "yarn workspace @wesib/wesib",
    "wesib:deps": "run‑p ‑‑aggregate‑output \"context‑values {@}\" \"namespace‑aliaser:c {@}\" \"render‑scheduler:c {@}\" ‑‑",
    "siteparts": "run‑s \"generic {@}\" \"siteparts:deps {@}\" \"siteparts:c {@}\" ‑‑",
    "siteparts:c": "run‑s ‑l \"siteparts:x {@}\" ‑‑",
    "siteparts:deps": "run‑s \"route‑match:c {@}\" \"hatsy:c {@}\" ‑‑",
    "siteparts:x": "yarn workspace @surol/siteparts"
  }
}

This is definitely not a way to go.

So I've created run‑z.

package.json looks like this now:

{
  "scripts": {
    "each": "run‑z ...proc7ts ...hatsy ...wesib ...siteparts",
    "each:p": "run‑z ‑‑bap ...dev‑kit ...run‑z ...each",
    "+dev‑kit/*": "run‑z +z ./dev‑kit...dev‑kit",
    "hatsy/*": "run‑z +z ./hatsy// ./hatsy/kit/packages//",
    "proc7ts/*": "run‑z +z ./proc7ts//",
    "+run‑z/*": "run‑z +z ./run‑z//",
    "siteparts/*": "run‑z +z ./siteparts",
    "wesib/*": "run‑z +z ./wesib//",
    "z": "run‑z +z:clean +z:test",
    "z:clean": "run‑z +each:p/clean",
    "z:test": "run‑z +each:p/lint,+each:p/cmd:jest/‑‑runInBand"
  }
}

So, now I can:

  • run yarn z clean build ‑‑all to rebuild all packages,
  • run yarn z build test ‑‑only hatsy to build and test a named subset of packages,
  • run yarn build ‑‑with‑deps inside particular package directory to build it along with its dependencies,
  • allow some tasks to run in parallel (e.g. lint and test),

...and many more.

run‑z takes some time to learn, but the result is satisfying.

Btw, you can try it without installing it. E.g. the following command

npx run‑z build:crm build:crm:storybook test:crm,lint:crm start:crm,start:crm:storybook

Would build CRM and storybook, then test and lint (in parallel to each other), then start both CRM and storybook (again, in parallel to each other).

(by Cazettolorus)

參考文件

  1. How to run multiple packages in development inside a Monorepo (CC BY‑SA 2.5/3.0/4.0)

#yarn-workspaces #lerna #monorepo #frontend #package






相關問題

如何使用帶有打字稿和輸出文件夾的紗線工作區? (How to use yarn workspaces with typescript and out folders?)

如何在 Monorepo 中運行多個開發包 (How to run multiple packages in development inside a Monorepo)

帶有許多 npm 腳本的 Monorepo (Monorepo with Many npm-scripts)

使用紗線工作區導出枚舉時出現意外的令牌錯誤 (Unexpected token error exporting enums using yarn workspaces)

如何在 Expo 應用示例嵌套文件夾中熱重載開發包? (How to hot reload a development package in an Expo app example nested folder?)

將 monorepo 包放在包文件夾下是一種約定,還是 yarn 工作區期望這樣? (Is putting monorepo packages under a package folder a convention, or do yarn workspace expect that?)

通過創建具有循環依賴關係的 monorepo 導致錯誤 (Causing an error by creating a monorepo with circular dependencies)

Monorepo – Yarn 工作區 Typescript Node.JS 項目 – 運行 nodemon 時找不到模塊 (Monorepo – Yarn workspaces Typescript Node.JS project – cannot find module when running nodemon)

紗線工作區為每個運行 shell 命令 (Yarn workspaces run shell command for each)

紗線工作區共享包未在 create-react-app 中加載 (yarn workspaces shared package does not load in create-react-app)

如何使用 Yarn 工作區將共享依賴項添加到 monorepo? (How do I add shared dependencies to a monorepo using Yarn workspaces?)

使用紗線工作區在monorepo中跨項目共享配置變量? (Sharing config variables across projects in a monorepo using yarn workspaces?)







留言討論