Lerna --多包儲存管理工具

記得要微笑發表於2022-06-09

lerna

最近在看vue-cli的原始碼部分,注意到這一個倉庫下維護了多個package,很好奇他是如何在一個repo中管理這些package的。

我們組現在也在使用元件庫的方式維護專案間共用的業務程式碼。有兩個元件庫,存在依賴的關係,目前聯調是通過npm link的方式,效能並不好,時常出現卡頓的問題。加上前一段時間組內分享vue3也提到了lerna,於是便決定仔細的調研一下這個工具,為接下里的元件庫優化助力。

lerna的文件還是很詳細的,因為全是英文的,考慮到閱讀問題,這裡我先是自己跑了幾個demo,然後做了中文翻譯。後續我會出一篇專門的lerna實戰篇

demo

lerna 是幹什麼的?

Lerna 是一個工具,它優化了使用 git 和 npm 管理多包儲存庫的工作流。

背景

1.將一個大的 package 分割成一些小的 packcage 便於分享,除錯

2.在多個 git 倉庫中更改容易變得混亂且難以跟蹤

3.在多個 git 倉庫中維護測試繁瑣

兩種工作模式

Fixed/Locked mode (default)

vue,babel 都是用這種,在 publish 的時候,所有的包版本都會更新,並且包的版本都是一致的,版本號維護在 lerna.jon 的 version 中

Independent mode

lerna init --independent

獨立模式,每個 package 都可以有自己的版本號。版本號維護在各自 package.json 的 version 中。每次釋出前都會提示已經更改的包,以及建議的版本號或者自定義版本號。這種方式相對第一種來說,更靈活

初始化專案

npm install -g lerna // 這裡是全域性安裝,也可以安裝為專案開發依賴,使用全域性方便後期使用命令列

mkdir lerna-repo

cd lerna-repo

lerna init // 初始化一個lerna專案結構,如果希望各個包使用單獨版本號可以加 -i | --independent

lerna init

標準的 lerna 目錄結構

  • 每個單獨的包下都有一個 package.json 檔案
  • 如果包名是帶 scope 的,例如@test/lerna,package.json 中,必須配置"publishConfig": {"access": "public"}
my-lerna-repo/

    package.json

    lerna.json

    LICENSE

    packages/

        package-1/

            package.json

        package-2/

            package.json

啟用 yarn Workspaces (強烈建議)

Workspaces can only be enabled in private projects.

預設是 npm, 每個子 package 下都有自己的 node_modules,通過這樣設定後,會把所有的依賴提升到頂層的 node_modules 中,並且在 node_modules 中連結本地的 package,便於除錯

注意:必須是 private 專案才可以開啟 workspaces

// package.json

"private": true,

"workspaces": [

    "packages/*"

],
 

// lerna.json

 
"useWorkspaces": true,

"npmClient": "yarn",

hoist: 提取公共的依賴到根目錄的node_moduels,可以自定義指定。其餘依賴安裝的package/node_modeles中,可執行檔案必須安裝在package/node_modeles

workspaces: 所有依賴全部在跟目錄的node_moduels,除了可執行檔案

hoist vs workspaces

常用命令

lerna init

初始化 lerna 專案

  • -i, --independent 獨立版本模式

[lerna create <name> [loc]](https://github.com/lerna/lern...

建立一個 packcage

  • --access 當使用scope package時(@qinzhiwei/lerna),需要設定此選項 可選值: "public", "restricted"
  • --bin 建立可執行檔案 --bin
  • --description 描述 [字串]
  • --dependencies 依賴,用逗號分隔 [陣列]
  • --es-module 初始化一個轉化的Es Module [布林]
  • --homepage 原始碼地址 [字串]
  • --keywords 關鍵字數 [陣列]
  • --license 協議 字串
  • --private 是否私有倉庫 [布林]
  • --registry 源 [字串]
  • --tag 釋出的標籤 [字串]
  • -y, --yes 跳過所有的提示,使用預設配置 [布林]

lerna add

為匹配的 package 新增本地或者遠端依賴,一次只能新增一個依賴

$ lerna add <package>[@version] [--dev] [--exact] [--peer]

執行該命令時做的事情:

  1. 為匹配到的 package 新增依賴
  2. 更改每個 package 下的 package.json 中的依賴項屬性
Command Options

以下幾個選項的含義和npm install時一致

  • --dev
  • --exact
  • --peer 同級依賴,使用該package需要在專案中同時安裝的依賴
  • --registry
  • --no-bootstrap 跳過 lerna bootstrap,只在更改對應的 package 的 package.json 中的屬性

所有的過濾選項都支援

Examples

# Adds the module-1 package to the packages in the 'prefix-' prefixed folders

lerna add module-1 packages/prefix-*

  

# Install module-1 to module-2

lerna add module-1 --scope=module-2

  

# Install module-1 to module-2 in devDependencies

lerna add module-1 --scope=module-2 --dev

  

# Install module-1 to module-2 in peerDependencies

lerna add module-1 --scope=module-2 --peer

  

# Install module-1 in all modules except module-1

lerna add module-1

  

# Install babel-core in all modules

lerna add babel-core

lerna bootstrap

將本地 package 連結在一起並安裝依賴

執行該命令式做了一下四件事:

1.為每個 package 安裝依賴

2.連結相互依賴的庫到具體的目錄,例如:如果 lerna1 依賴 lerna2,且版本剛好為本地版本,那麼會在 node_modules 中連結本地專案,如果版本不滿足,需按正常依賴安裝

3.在 bootstraped packages 中 執行 npm run prepublish

4.在 bootstraped packages 中 執行 npm run prepare

lerna bootstrap

lerna bootstrap

Command Options
  • --hoist 匹配 [glob] 依賴 提升到根目錄 [預設值: '**'], 包含可執行二進位制檔案的依賴項還是必須安裝在當前 package 的 node_modules 下,以確保 npm 指令碼的執行
  • --nohoist 和上面剛好相反 [字串]
  • --ignore-prepublish 在 bootstraped packages 中不再執行 prepublish 生命週期中的指令碼 [布林]
  • --ignore-scripts 在 bootstraped packages 中不再執行任何生命週期中的指令碼 [布林]
  • --npm-client 使用的 npm 客戶端(npm, yarn, pnpm, ...) [字串]
  • --registry 源 [字串]
  • --strict 在 bootstrap 的過程中不允許發出警告,避免花銷更長的時間或者導致其他問題 [布林]
  • --use-workspaces 啟用 yarn 的 workspaces 模式 [布林]
  • --force-local 無論版本範圍是否匹配,強制本地同級連結 [布林]
  • --contents 子目錄用作任何連結的源。必須適用於所有包 字串

lerna link

將本地相互依賴的 package 相互連線。例如 lerna1 依賴 lerna2,且版本號剛好為本地的 lerna2,那麼會在 lerna1 下 node_modules 中建立軟連指向 lerna2

Command Options
  • --force-local 無論本地 package 是否滿足版本需求,都連結本地的
// 指定軟鏈到package的特定目錄

"publishConfig": {

    "directory": "dist" // bootstrap的時候軟鏈package下的dist目錄 package-1/dist => node_modules/package-1

}

lerna list

list 子命令
  • lerna ls: 等同於 lerna list本身,輸出專案下所有的 package
  • lerna ll: 輸出專案下所有 package 名稱、當前版本、所在位置
  • lerna la: 輸出專案下所有 package 名稱、當前版本、所在位置,包括 private package
Command Options

所有的過濾選項都支援

--json

以 json 形式展示

$ lerna ls --json

[

    {

        "name": "package-1",

        "version": "1.0.0",

        "private": false,

        "location": "/path/to/packages/pkg-1"

    },

    {

        "name": "package-2",

        "version": "1.0.0",

        "private": false,

        "location": "/path/to/packages/pkg-2"

    }

]
--ndjson

newline-delimited JSON展示資訊

$ lerna ls --ndjson

{"name":"package-1","version":"1.0.0","private":false,"location":"/path/to/packages/pkg-1"}

{"name":"package-2","version":"1.0.0","private":false,"location":"/path/to/packages/pkg-2"}
--all

Alias: -a

顯示預設隱藏的 private package

$ lerna ls --all

package-1

package-2

package-3 (private)
--long

Alias: -l

顯示包的版本、位置、名稱

$ lerna ls --long

package-1 v1.0.1 packages/pkg-1

package-2 v1.0.2 packages/pkg-2

  

$ lerna ls -la

package-1 v1.0.1 packages/pkg-1

package-2 v1.0.2 packages/pkg-2

package-3 v1.0.3 packages/pkg-3 (private)
--parseable

Alias: -p

顯示包的絕對路徑

In --long output, each line is a :-separated list: ::[:flags..]

$ lerna ls --parseable

/path/to/packages/pkg-1

/path/to/packages/pkg-2

  

$ lerna ls -pl

/path/to/packages/pkg-1:package-1:1.0.1

/path/to/packages/pkg-2:package-2:1.0.2

  

$ lerna ls -pla

/path/to/packages/pkg-1:package-1:1.0.1

/path/to/packages/pkg-2:package-2:1.0.2

/path/to/packages/pkg-3:package-3:1.0.3:PRIVATE
--toposort

按照拓撲順序(dependencies before dependents)對包進行排序,而不是按目錄對包進行詞法排序。

$ json dependencies <packages/pkg-1/package.json

{

    "pkg-2": "file:../pkg-2"

}

  

$ lerna ls --toposort

package-2

package-1
--graph

將依賴關係圖顯示為 JSON 格式的鄰接表 adjacency list.

$ lerna ls --graph

{

    "pkg-1": [

        "pkg-2"

    ],

    "pkg-2": []

}

  

$ lerna ls --graph --all

{

    "pkg-1": [

       "pkg-2"

    ],

    "pkg-2": [

        "pkg-3"

    ],

    "pkg-3": [

        "pkg-2"

    ]

}

lerna changed

列出自上次釋出(打 tag)以來本地發生變化的 package

注意: lerna publishlerna versionlerna.json配置同樣影響lerna changed。 例如 command.publish.ignoreChanges.

Command Options

lerna changed 支援 lerna ls的所有標記:

lerna 不支援過濾選項, 因為lerna version or lerna publish不支援過濾選項.

lerna changed 支援 lerna version (the others are irrelevant)的過濾選項:

lerna import

lerna import 

將現有的 package 匯入到 lerna 專案中。可以保留之前的原始提交作者,日期和訊息將保留。

注意:如果要在一個新的 lerna 中引入,必須至少有個 commit

Command Options
  • --flatten 處理合並衝突
  • --dest 指定引入包的目錄
  • --preserve-commit 保持引入專案原有的提交者資訊

lerna clean

lerna clean

移除所有 packages 下的 node_modules,並不會移除根目錄下的

所有的過濾選項都支援

lerna diff

檢視自上次釋出(打 tag)以來某個 package 或者所有 package 的變化

$ lerna diff [package]

  

$ lerna diff

# diff a specific package

$ lerna diff package-name
Similar to lerna changed. This command runs git diff.

lerna exec

在每個 package 中執行任意命令,用波折號(--)分割命令語句

使用方式
$ lerna exec -- <command> [..args] # runs the command in all packages

$ lerna exec -- rm -rf ./node_modules

$ lerna exec -- protractor conf.js

可以通過LERNA_PACKAGE_NAME變數獲取當前 package 名稱:

$ lerna exec -- npm view $LERNA_PACKAGE_NAME

也可以通過LERNA_ROOT_PATH獲取根目錄絕對路徑:

$ lerna exec -- node $LERNA_ROOT_PATH/scripts/some-script.js
Command Options

所有的過濾選項都支援

$ lerna exec --scope my-component -- ls -la
  • --concurrenty

使用給定的數量進行併發執行(除非指定了

--parallel

)。

輸出是經過管道過濾,存在不確定性。

如果你希望命令一個接著一個執行,可以使用如下方式:

$ lerna exec --concurrency 1 -- ls -la
  • --stream

從子程式立即輸出,字首是包的名稱。該方式允許交叉輸出:

$ lerna exec --stream -- babel src -d lib

![lerna exec --stream -- babel src -d lib]()

  • --parallel

--stream很像。但是完全忽略了併發性和排序,立即在所有匹配的包中執行給定的命令或指令碼。適合長時間執行的程式。例如處於監聽狀態的babel src -d lib -w

$ lerna exec --parallel -- babel src -d lib -w

注意:

建議使用命令式控制包的範圍。

因為過多的程式可能會損害shell的穩定。例如最大檔案描述符限制

  • --no-bail
# Run a command, ignoring non-zero (error) exit codes

$ lerna exec --no-bail <command>

預設情況下,如果一但出現命令報錯就會退費程式。使用該命令會禁止此行為,跳過改報錯行為,繼續執行其他命令

  • --no-prefix

在輸出中不顯示 package 的名稱

  • --profile

生成一個 json 檔案,可以在 chrome 瀏覽器(devtools://devtools/bundled/devtools_app.html)檢視效能分析。通過配置--concurrenty可以開啟固定數量的子程式數量

![lerna exec --stream -- babel src -d lib]()

$ lerna exec --profile -- <command>
注意: 僅在啟用拓撲排序時分析。不能和 --parallel and --no-sort一同使用。
  • --profile-location

設定分析檔案存放位置

$ lerna exec --profile --profile-location=logs/profile/ -- <command>

lerna run

在每個 package 中執行 npm 指令碼

使用方法
$ lerna run <script> -- [..args] # runs npm run my-script in all packages that have it

$ lerna run test

$ lerna run build

  

# watch all packages and transpile on change, streaming prefixed output

$ lerna run --parallel watch
Command Options
  • --npm-client

設定npm客戶端,預設是npm

$ lerna run build --npm-client=yarn

也可以在lerna.json配置:

{

    "command": {

        "run": {

            "npmClient": "yarn"

        }

    }

}
  • 其餘同lerna exec

lerna version

生成新的唯一版本號

bumm version:在使用類似 github 程式時,升級版本號到一個新的唯一值

使用方法
lerna version 1.0.1 # 顯示指定

lerna version patch # 語義關鍵字

lerna version # 從提示中選擇

當執行時,該命令做了一下事情:

1.識別從上次打標記釋出以來發生變更的 package 2.版本提示 3.修改 package 的後設資料反映新的版本,在根目錄和每個 package 中適當執行lifecycle scripts 4.在 git 上提交改變並對該次提交打標記(git commit & git tag) 5.提交到遠端倉庫(git push)

![lerna version]()

Positionals
semver bump
lerna version [major | minor | patch | premajor | preminor | prepatch | prerelease]

# uses the next semantic version(s) value and this skips `Select a new version for...` prompt

When this positional parameter is passed, lerna version will skip the version selection prompt and increment the version by that keyword.

You must still use the --yes flag to avoid all prompts.

Prerelease

如果某些 package 是預釋出版本(e.g. 2.0.0-beta.3),當你執行lerna version配合語義化版本時(major, minor, patch),它將釋出之前的預釋出版本和自上次釋出以來改變過的 packcage。

對於使用常規提交的專案,可以使用如下標記管理預釋出版本:

  • --conventional-prerelease: 釋出當前變更為預釋出版本(即便採用的是固定模式,也會單獨升級該 package)
  • --conventional-graduate: 升級預釋出版本為穩定版(即便採用的是固定模式,也會單獨升級該 package)

當一個 package 為預發版本時,不使用上述標記,使用lerna version --conventional-commits,也會按照預發版本升級繼續升級當前 package。

lerna la

lerna version --conventional-commits

Command Options
--allow-branch

A whitelist of globs that match git branches where lerna version is enabled.

It is easiest (and recommended) to configure in lerna.json, but it is possible to pass as a CLI option as well.

設定可以呼叫lerna version命令的分支白名單,也可以在lerna.json中設定

{

    "command": {

        "version": {

            "allowBranch": ["master", "beta/*", "feature/*"]

        }

    }

}
--amend
lerna version --amend

# commit message is retained, and `git push` is skipped.

預設情況下如果暫存區有未提交的內容,lerna version會失敗,需要提前儲存本地內容。使用該標記可以較少 commit 的次數,將當前變更內容隨著本次版本變化一次 commit。並且不會git push

--changelog-preset
lerna version --conventional-commits --changelog-preset angular-bitbucket

預設情況下,changelog 預設設定為angular。在某些情況下,您可能需要使用另一個預置或自定義。

--conventional-commits
lerna version --conventional-commits

當使用這個標誌執行時,lerna 版本將使用傳統的提交規範/Conventional Commits Specification確定版本並生成CHANGELOG.md

傳入 --no-changelog 將阻止生成或者更新CHANGELOG.md.

--conventional-graduate
lerna version --conventional-commits --conventional-graduate=package-2,package-4

  

# force all prerelease packages to be graduated

lerna version --conventional-commits --conventional-graduate

但使用該標記時,lerna vesion將升級指定的 package(用逗號分隔)或者使用*指定全部 package。和--force-publish很像,無論當前的 HEAD 是否釋出,該命令都會起作用,任何沒有預釋出的 package 將會被忽略。如果未指定的包(如果指定了包)或未預先發布的包發生了更改,那麼這些包將按照它們通常使用的--conventional-commits進行版本控制。

"升級"一個包意味著將一個預釋出的包升級為釋出版本,例如package-1@1.0.0-alpha.0 => package-1@1.0.0

注意: 當指定包時,指定包的依賴項將被釋放,但不會被“升級”。必須和--conventional-commits一起使用
--conventional-prerelease
lerna version --conventional-commits --conventional-prerelease=package-2,package-4

  

# force all changed packages to be prereleased

lerna version --conventional-commits --conventional-prerelease

當使用該標記時,lerna version將會以預釋出的版本釋出指定的 package(用逗號分隔)或者使用*指定全部 package。

--create-release
lerna version --conventional-commits --create-release github

lerna version --conventional-commits --create-release gitlab

當使用此標誌時,lerna version會基於改變的 package 建立一個官方正式的 GitHub 或 GitLab 版本記錄。需要傳遞--conventional-commits去建立 changlog。

GithuB 認證,以下環境變數需要被定義。

  • GH_TOKEN (required) - Your GitHub authentication token (under Settings > Developer settings > Personal access tokens).
  • GHE_API_URL - When using GitHub Enterprise, an absolute URL to the API.
  • GHE_VERSION - When using GitHub Enterprise, the currently installed GHE version. Supports the following versions.

GitLab 認證,以下環境變數需要被定義。

  • GL_TOKEN (required) - Your GitLab authentication token (under User Settings > Access Tokens).
  • GL_API_URL - An absolute URL to the API, including the version. (Default: https://gitlab.com/api/v4)
注意: 不允許和--no-changelog一起使用

這個選項也可以在lerna.json中配置:

{

    "changelogPreset": "angular"

}

If the preset exports a builder function (e.g. conventional-changelog-conventionalcommits), you can specify the preset configuration too:

{

    "changelogPreset": {

        "name": "conventionalcommits",

        "issueUrlFormat": "{{host}}/{{owner}}/{{repository}}/issues/{{id}}"

    }

}

![lerna version --conventional-commits --create-release github]()

--exact
lerna version --exact
--force-publish
lerna version --force-publish=package-2,package-4

  

# force all packages to be versioned

lerna version --force-publish

強制更新版本

這個操作將跳過lerna changed檢查,即便 package 沒有做任何變更也會更新版本
--git-remote
lerna version --git-remote upstream

將本地commitpush 到指定的遠端殘酷,預設是origin

--ignore-changes

變更檢測時忽略的檔案

lerna version --ignore-changes '**/*.md' '**/__tests__/**'

建議在根目錄lerna.json中配置:

{

    "ignoreChanges": ["**/__fixtures__/**", "**/__tests__/**", "**/*.md"]

}

--no-ignore-changes 禁止任何現有的忽略配置:

--ignore-scripts

禁止lifecycle scripts

--include-merged-tags
lerna version --include-merged-tags
--message
-m`別名,等價於`git commit -m
lerna version -m "chore(release): publish %s"

# commit message = "chore(release): publish v1.0.0"

  

lerna version -m "chore(release): publish %v"

# commit message = "chore(release): publish 1.0.0"

  

# When versioning packages independently, no placeholders are replaced

lerna version -m "chore(release): publish"

# commit message = "chore(release): publish

#

# - package-1@3.0.1

# - package-2@1.5.4"

也可以在lerna.json配置:

{

    "command": {

        "version": {

            "message": "chore(release): publish %s"

        }

    }

}
--no-changelog
lerna version --conventional-commits --no-changelog

不生成CHANGELOG.md

注意:不可以和--create-release一起使用
--no-commit-hooks

預設情況下,lerna version會執行git commit hooks。使用該標記,阻止git commit hooks執行。

--no-git-tag-version

預設情況下,lerna version 會提交變更到package.json檔案,並打標籤。使用該標記會阻止該預設行為。

--no-granular-pathspec

預設情況下,在建立版本的過程中,會執行git add -- packages/*/package.json操作。

也可以更改預設行為,提交除了package.json以外的資訊,前提是必須做好敏感資料的保護。

// leran.json

{

    "version": "independent",

    "granularPathspec": false

}
--no-private

排除private:true的 package

--no-push

By default, lerna version will push the committed and tagged changes to the configured git remote.

Pass --no-push to disable this behavior.

--preid
lerna version prerelease

# uses the next semantic prerelease version, e.g.

# 1.0.0 => 1.0.1-alpha.0

  

lerna version prepatch --preid next

# uses the next semantic prerelease version with a specific prerelease identifier, e.g.

# 1.0.0 => 1.0.1-next.0

版本語義化

--sign-git-commit

npm version option

--sign-git-tag

npm version option

--force-git-tag

取代已存在的tag

--tag-version-prefix

自定義版本字首。預設為v

# locally

lerna version --tag-version-prefix=''

# on ci

lerna publish from-git --tag-version-prefix=''
--yes
lerna version --yes

# skips `Are you sure you want to publish these packages?`

跳過所有提示

生成更新日誌CHANGELOG.md

如果你在使用多包儲存一段時間後,開始使用--conventional-commits標籤,你也可以使用conventional-changelog-clilerna exec為之前的版本建立 changelog:

# Lerna does not actually use conventional-changelog-cli, so you need to install it temporarily

npm i -D conventional-changelog-cli

# Documentation: `npx conventional-changelog --help`

  

# fixed versioning (default)

# run in root, then leaves

npx conventional-changelog --preset angular --release-count 0 --outfile ./CHANGELOG.md --verbose

npx lerna exec --concurrency 1 --stream -- 'conventional-changelog --preset angular --release-count 0 --commit-path $PWD --pkg $PWD/package.json --outfile $PWD/CHANGELOG.md --verbose'

  

# independent versioning

# (no root changelog)

npx lerna exec --concurrency 1 --stream -- 'conventional-changelog --preset angular --release-count 0 --commit-path $PWD --pkg $PWD/package.json --outfile $PWD/CHANGELOG.md --verbose --lerna-package $LERNA_PACKAGE_NAME'

If you use a custom --changelog-preset, you should change --preset value accordingly in the example above.

Lifecycle Scripts
// preversion: Run BEFORE bumping the package version.

// version: Run AFTER bumping the package version, but BEFORE commit.

// postversion: Run AFTER bumping the package version, and AFTER commit.

Lerna will run npm lifecycle scripts during lerna version in the following order:

  1. Detect changed packages, choose version bump(s)
  2. Run preversion lifecycle in root
  3. For each changed package, in topological order (all dependencies before dependents):
  4. Run preversion lifecycle
  5. Update version in package.json
  6. Run version lifecycle
  7. Run version lifecycle in root
  8. Add changed files to index, if enabled
  9. Create commit and tag(s), if enabled
  10. For each changed package, in lexical order (alphabetical according to directory structure):
  11. Run postversion lifecycle
  12. Run postversion lifecycle in root
  13. Push commit and tag(s) to remote, if enabled
  14. Create release, if enabled

lerna publish

lerna publish # 釋出自上次發版依賴更新的packages

lerna publish from-git # 顯示的釋出在當前提交中打了tag的packages

lerna publish from-package # 顯示的釋出當前版本在登錄檔中(registry)不存在的packages(之前沒有釋出到npm上)

執行時,該命令執行以下操作之一:

  • 釋出自上次發版依賴更新的 packages(背後呼叫lerna version判斷)
  • 這是 2.x 版本遺留的表現
  • 顯示的釋出在當前提交中打了 tag 的 packages
  • 顯示的釋出在最新的提交中當前版本在登錄檔中(registry)不存在的 packages(之前沒有釋出到 npm 上)
  • 釋出在之前提交中未版本化的進行過金絲雀部署的 packages(canary release)
Lerna 無法釋出私有的 packcage("private":true)

在所有釋出操作期間,適當的生命週期指令碼(lifecycle scripts)在根目錄和每個包中被呼叫(除非被--ignore-scripts禁用)。

Positionals
  • bump from-git

除了lerna version支援的 semver 關鍵字之外,lerna publish還支援from-git關鍵字。這將識別lerna version標記的包,並將它們釋出到 npm。這在 CI 場景中非常有用,在這種場景中,您希望手動增加版本,但要通過自動化過程一致地釋出包內容本身

  • bump from-package

from-git關鍵字相似,除了要釋出的軟體包列表是通過檢查每個package.json並確定登錄檔中是否沒有任何軟體包版本來確定的。 登錄檔中不存在的任何版本都將被髮布。 當先前的lerna publish未能將所有程式包釋出到登錄檔時,此功能很有用。

Command Options

lerna publish除了支援一下選項外,還支援lerna version的所有選項:

--canary
lerna publish --canary

# 1.0.0 => 1.0.1-alpha.0+${SHA} of packages changed since the previous commit

# a subsequent canary publish will yield 1.0.1-alpha.1+${SHA}, etc

  

lerna publish --canary --preid beta

# 1.0.0 => 1.0.1-beta.0+${SHA}

  

# The following are equivalent:

lerna publish --canary minor

lerna publish --canary preminor

# 1.0.0 => 1.1.0-alpha.0+${SHA}

針對最近一次提交發生改變的 package,做更精細的版本控制。類似於金絲雀部署,構建生產環境的容錯測試。如果是統一的版本控制,其他 package 版本號不做升級,只針對變更的 package 做精準除錯。

lerna publish --canary

--contents

子目錄釋出。子目錄中必須包含 package.json。

lerna publish --contents dist

# publish the "dist" subfolder of every Lerna-managed leaf package
--dist-tag
lerna publish --dist-tag custom-tag

自定義 npm釋出標籤。預設是latest

該選項可以用來定義prerelease 或者 beta 版本

注意

:

npm install my-package

預設安裝的是

latest

版本.

安裝其他版本 npm install my-package@prerelease.

lerna publish --canary

--git-head

只可以和from-package配合使用,根據指定的git 釋出

也可以使用環境變數指定

lerna publish from-package --git-head ${CODEBUILD_RESOLVED_SOURCE_VERSION}
--graph-type
npm`上構建`package dependencies`所採用的方式,預設是`dependencies`,只列出`dependencies`。`all`會列出`dependencies` 和 `devDependencies
lerna publish --graph-type all

也可以通過lerna.json配置:

{

    "command": {

        "publish": {

            "graphType": "all"

        }

    }

}

lerna publish --graph-type all

--ignore-scripts

關閉npm指令碼生命週期事件的觸發

--ignore-prepublish

近關閉npm指令碼生命週期 prepublish事件的觸發

--legacy-auth

釋出前的身份驗證

lerna publish --legacy-auth aGk6bW9t
--no-git-reset

預設情況下,lerna publish會把暫存區內容全部提交。即lerna publish釋出時更改了本地 package 中的 version,也一併提交到 git。

lerna publish

未避免上述情況發生,可以使用--no-git-reset。這對作為管道配置--canary使用時非常有用。例如,已經改變的package.json的版本號可能會在下一步操作所用到(例如 Docker builds)。

lerna publish --no-git-reset
--no-granular-pathspec

By default, lerna publish will attempt (if enabled) to git checkout only the leaf package manifests that are temporarily modified during the publishing process. This yields the equivalent of git checkout -- packages/*/package.json, but tailored to exactly what changed.

If you know you need different behavior, you'll understand: Pass --no-granular-pathspec to make the git command literally git checkout -- .. By opting into this pathspec, you must have all intentionally unversioned content properly ignored.

This option makes the most sense configured in lerna.json, as you really don't want to mess it up:

{

    "version": "independent",

    "granularPathspec": false

}

The root-level configuration is intentional, as this also covers the identically-named option in lerna version.

--no-verify-access

預設情況下lerna會驗證已登入使用者對即將釋出的 package 的許可權。使用此標記將會阻止該預設行為。

如果你正在使用第三方的不支援npm access ls-packages的 npm 庫,需要使用該標記。或者在lerna.json中設定command.publish.verifyAccessfalse

謹慎使用
--otp

當釋出需要雙重認證的 package 時,需要指定一次性密碼

lerna publish --otp 123456

當開啟npm 雙重認證後,可以通過配置對 account 和 npm 操作的進行二次驗證。需要 npm 版本大於5.5.0

驗證工具

Two-factor authentication

密碼的有效時長為 30s,過期後需要重新輸入驗證
--preid

Unlike the lerna version option of the same name, this option only applies to --canary version calculation.

--canary 配合使用,指定語義化版本

lerna publish --canary

# uses the next semantic prerelease version, e.g.

# 1.0.0 => 1.0.1-alpha.0

  

lerna publish --canary --preid next

# uses the next semantic prerelease version with a specific prerelease identifier, e.g.

# 1.0.0 => 1.0.1-next.0

當使用該標記時,lerna publish --canary 將增量改變 premajor, preminor, prepatch, 或者 prerelease 的語義化版本。

語義化版本(prerelease identifier)

--pre-dist-tag
lerna publish --pre-dist-tag next

效果和--dist-tag一樣。只適用於釋出的預釋出版本。

--registry
--tag-version-prefix

更改標籤字首

如果分割lerna versionlerna publish,需要都設定一遍:

# locally

lerna version --tag-version-prefix=''

  

# on ci

lerna publish from-git --tag-version-prefix=''

也可以在lerna.json中配置該屬性,效果等同於上面兩條命令:

{

"tagVersionPrefix": "",

"packages": ["packages/*"],

"version": "independent"

}
--temp-tag

當傳遞時,這個標誌將改變預設的釋出過程,首先將所有更改過的包釋出到一個臨時的 dis tag (' lerna-temp ')中,然後將新版本移動到'--dist-tag '(預設為' latest ')配置的 dist-tag 中。

這通常是沒有必要的,因為 Lerna 在預設情況下會按照拓撲順序(所有依賴先於依賴)釋出包

--yes
lerna publish --canary --yes

# skips `Are you sure you want to publish the above changes?`

跳過所有的確認提示

Continuous integration (CI)很有用,自動回答釋出時的確認提示

每個 package 的配置

每個 package 可以通過更改publishConfig,來改變釋出時的一些行為。

publishConfig.access

當釋出一個scope的 package(e.g., @mycompany/rocks)時,必須設定access

"publishConfig": {

    "access": "public"

}
  • 如果在沒有使用 scope 的 package 中使用該屬性,將失敗
  • 如果你希望保持一個 scope 的 package 為私有(i.e., "restricted"),那麼就不需要設定

注意,這與在包中設定"private":true不一樣;如果設定了private欄位,那麼在任何情況下都不會發布該包。

publishConfig.registry
"publishConfig": {

    "registry": "http://my-awesome-registry.com/"

}
  • 也可以通過--registry或者在 lerna.json 中設定command.publish.registry進行全域性控制
publishConfig.tag

自定義該包釋出時的標籤tag:

"publishConfig": {

    "tag": "flippin-sweet"

}
  • --dist-tag將覆蓋每個 package 中的值
  • 在使用[--canary]時該值將被忽略
publishConfig.directory

非標準欄位,自定義釋出的檔案

"publishConfig": {

    "directory": "dist"

}
npm 指令碼生命週期
// prepublish: Run BEFORE the package is packed and published.

// prepare: Run BEFORE the package is packed and published, AFTER prepublish, BEFORE prepublishOnly.

// prepublishOnly: Run BEFORE the package is packed and published, ONLY on npm publish.

// prepack: Run BEFORE a tarball is packed.

// postpack: Run AFTER the tarball has been generated and moved to its final destination.

// publish: Run AFTER the package is published.

// postpublish: Run AFTER the package is published.

lerna publish執行時,按如下順序呼叫npm 指令碼生命週期

  1. 如果採用隱式版本管理,則執行所有 version lifecycle scripts
  2. Run prepublish lifecycle in root, if enabled
  3. Run prepare lifecycle in root
  4. Run prepublishOnly lifecycle in root
  5. Run prepack lifecycle in root
  6. For each changed package, in topological order (all dependencies before dependents):
  7. Run prepublish lifecycle, if enabled
  8. Run prepare lifecycle
  9. Run prepublishOnly lifecycle
  10. Run prepack lifecycle
  11. Create package tarball in temp directory via JS API
  12. Run postpack lifecycle
  13. Run postpack lifecycle in root
  14. For each changed package, in topological order (all dependencies before dependents):
  15. Publish package to configured registry via JS API
  16. Run publish lifecycle
  17. Run postpublish lifecycle
  18. Run publish lifecycle in root
  • To avoid recursive calls, don't use this root lifecycle to run lerna publish
  1. Run postpublish lifecycle in root
  2. Update temporary dist-tag to latest, if enabled

過濾選項

  • --scope 為匹配到的 package 安裝依賴 [字串]
  • --ignore 和上面正相反 [字串]
  • --no-private 排除 private 的 packcage
  • --since 包含從指定的[ref]依賴改變的 packages,如果沒有[ref],預設是最近的 tag
  • --exclude-dependents 當使用—since 執行命令時,排除所有傳遞依賴項,覆蓋預設的“changed”演算法 [布林]
  • --include-dependents 啟動命令式包含所有傳遞的依賴項,無視 --scope, --ignore, or --since [布林]
  • --include-dependencies 啟動命令式包含所有傳遞的依賴項,無視 --scope, --ignore, or --since [布林]
  • --include-merged-tags 在使用—since 執行命令時,包含來自合併分支的標記 [布林]

全域性選項

  • --loglevel 列印日誌的級別 [字串] 預設值: info
  • --concurrency 並行任務時啟動的程式數目 [數字] [預設值: 4]
  • --reject-cycles 如果 package 之間相互依賴,則失敗 [布林]
  • --no-progress 關閉程式進度條 [布林]
  • --no-sort 不遵循拓撲排序 [布林]
  • --max-buffer 設定子命令執行的 buffer(以位元組為單位) [數字]
  • -h, --help 顯示幫助資訊
  • -v, --version 顯示版本資訊

Concept

lerna.json

{

    "version": "1.1.3", // 版本

    "npmClient": "npm", // npm客戶端

    "command": {

        "publish": {

            "ignoreChanges": ["ignored-file", "*.md"], // 釋出檢測時忽略的檔案

            "message": "chore(release): publish", // 釋出時 tag標記的版本資訊

            "registry": "https://npm.pkg.github.com" // 源

    },

    "bootstrap": {

        "ignore": "component-*", // bootstrap時忽略的檔案

        "npmClientArgs": ["--no-package-lock"], // 命令列引數

    },

    "version": {

        "allowBranch": [ // 允許執行lerna version的分支

                "master",

                "feature/*"

        ],

    "message": "chore(release): publish %s" // 建立版本時 tag標記的版本資訊

    }

},

    "ignoreChanges": [

        "**/__fixtures__/**",

        "**/__tests__/**",

        "**/*.md"

    ],

    "packages": ["packages/*"],// package位置

}

Wizard

這裡推薦一個新手引導工具lerna-wizard

lerna-wizard

相關文章