前言
由于公司項(xiàng)目大多采用react-native實(shí)現(xiàn)档悠,在APP內(nèi)部運(yùn)行戏自,但也要有H5的使用場(chǎng)景,以前很多項(xiàng)目都開發(fā)多套代碼邓嘹, 造成人力成本大幅浪費(fèi)酣栈,基于此, 我主導(dǎo)開發(fā)了一套R(shí)N轉(zhuǎn)H5的一套開發(fā)框架以及一整套的代碼規(guī)范汹押、推送CND等一系列的前端工程化體系矿筝, 然而有較多的私有庫(kù)發(fā)布到公司內(nèi)部NPM鏡像上,私有庫(kù)多了棚贾,每個(gè)庫(kù)之間又相互依賴窖维,一段時(shí)間下來,版本號(hào)就很難管理妙痹,大多數(shù)時(shí)候需要手動(dòng)更新版本依賴铸史;
其實(shí)babel的重要貢獻(xiàn)者Jamie Kyle1,在為 Babel 6 工作的過程中發(fā)現(xiàn)所有東西都拆分成漂亮的小插件包怯伊,但同時(shí)也就需要管理數(shù)十個(gè)軟件包琳轿, 也遇到同樣的問題。因此震贵,多包存儲(chǔ)庫(kù)管理工具 Lerna 應(yīng)運(yùn)而生利赋。為讓項(xiàng)目更好用水评,他對(duì)項(xiàng)目進(jìn)行了多次重寫猩系,試圖讓架構(gòu)更完善。
什么是Lerna
Lerna官網(wǎng)對(duì)此給出了官方的解釋:Lerna是一個(gè)管理包含多個(gè)軟件包的JavaScript項(xiàng)目的工具中燥。它可以:
1寇甸、解決包之間的依賴關(guān)系。
2疗涉、通過git倉(cāng)庫(kù)檢測(cè)改動(dòng)拿霉,自動(dòng)同步跷叉。
3迎捺、根據(jù)相關(guān)的git提交的commit,生成CHANGELOG测萎。
Lerna是一個(gè)命令行工具闹伪,可以將其安裝在系統(tǒng)全局沪铭。簡(jiǎn)單的命令說明,可以使用:lerna -h查看命令幫助偏瓤。
兩種包管理模式
默認(rèn)的為固定模式(Fixed mode)杀怠,當(dāng)使用lerna init命令初始化項(xiàng)目時(shí),就默認(rèn)為固定模式厅克,也可以使用 lerna init --independent 命令初始化項(xiàng)目赔退,這個(gè)時(shí)候就為獨(dú)立模式(Independent mode)。
固定模式中,packages下的所有包共用一個(gè)版本號(hào)(version)硕旗,會(huì)自動(dòng)將所有的包綁定到一個(gè)版本號(hào)上(該版本號(hào)也就是lerna.json中的version字段)窗骑,所以任意一個(gè)包發(fā)生了更新,這個(gè)共用的版本號(hào)就會(huì)發(fā)生改變漆枚。
獨(dú)立模式允許每一個(gè)包有一個(gè)獨(dú)立的版本號(hào)慧域,在使用lerna publish命令時(shí),可以為每個(gè)包單獨(dú)制定具體的操作浪读,同時(shí)可以只更新某一個(gè)包的版本號(hào)昔榴。此種模式時(shí),lerna.json中的version字段指定為independent即可碘橘。
添加lerna.json配置
{
"version": "0.7.30",
"packages": [
"packages/package-1",
"packages/package-2",
"packages/package-3",
"packages/package-4"
],
"command": {
"publish": {
"message": "chore(release): publish %s"
},
"bootstrap": {
"npmClientArgs": [
"--no-package-lock"
]
}
},
"npmClient": "npm"
}
備注: 上面的配置文件中互订,部分字段做下如下說明:
version指定的是所有包的統(tǒng)一版本號(hào);對(duì)于independent模式痘拆,這個(gè)字段請(qǐng)指定為independent仰禽;
npmClient指定的是npm的客戶端。默認(rèn)的纺蛆,lerna將使用npm吐葵。讀者也可依所需將程序設(shè)置為yarn,甚至cnpm等等桥氏。
command字段温峭,可以對(duì)publish和bootstrap命令進(jìn)行參數(shù)傳遞和命令定制。如:command.publish.ignoreChanges字支,用來設(shè)置一些忽略的文件凤藏,以避免無關(guān)文件的提交對(duì)于版本號(hào)的變更,如README.md等等堕伪。command.bootstrap.npmClientArgs指定在bootstrap命令時(shí)揖庄,傳遞的默認(rèn)參數(shù),比如我們會(huì)常常使用--no-package-lock來禁止package-lock.json或yarn.lock等等欠雌。
packages字段指定包所在的目錄蹄梢。
常用命令
Lerna命令
初始一個(gè)多包的工程
lerna init
上述命令會(huì)初始化一個(gè)多包工程。初始化之后會(huì)在根目錄生成packages目錄富俄、lerna.json禁炒,如果使用independent模式,請(qǐng)使用命令:lerna init --independent
創(chuàng)建子包
lerna create <package> [-y]
在packages所指目錄下創(chuàng)建package包蛙酪。
添加包
lerna add <package>[@version] [--dev] [--exact] [--scope=module名]
上述命令會(huì)添加一個(gè)包package指明的軟件包齐苛。
指定--dev是添加在devDependencies中。
指定--exact桂塞,則將用精確匹配的版本添加包凹蜂。
指定--scope將只在此指明的模塊中安裝這個(gè)軟件包,否則將在所有packages目錄中的包中安裝。
對(duì)于packages目錄下的子包玛痊,將通過設(shè)立systemlink來解決依賴汰瘫。
對(duì)于npm鏡像中存在的包,將安裝鏡像中的包擂煞。
運(yùn)行命令
運(yùn)行命令分為兩種:任意命令和npm scripts定義的命令混弥。
對(duì)于任意命令使用,lerna exec对省;對(duì)于npm scripts定義的命令使用lerna run
以lerna exec為例:
lerna exec [--concurrency number] [--stream] [--parallel] -- <command> [..args]此命令蝗拿,在所有包中運(yùn)行所指定的命令。
特別地蒿涎,lerna exec -- rm -rf ./node_modules將刪除所有包中的依賴哀托。lerna exec -- npm uninstall <package>將移除所有的package依賴。
lerna exec 和 lerna run 如需要每個(gè)子模塊相繼的執(zhí)行并按順序輸出劳秋,可以指定--concurrency 1仓手。
對(duì)于指定了--stream的命令,將把所有子進(jìn)程的輸出立即回顯此舉可能造成子進(jìn)程顯示順序交叉玻淑,為了分辨輸出來源嗽冒,每個(gè)輸出,會(huì)帶上包名补履;指定了--parallel的命令添坊,則會(huì)在scope指定的范圍內(nèi),并行地執(zhí)行相關(guān)地命令干像。
lerna run與上述命令不一樣的情況在于帅腌,lerna run build將在每一個(gè)包中scripts字段中執(zhí)行定義的build命令驰弄。
安裝所有依賴
lerna bootstrap
上述命令安裝所有的依賴麻汰、將所有的相關(guān)鏈接做好,同時(shí)在所有的包中運(yùn)行npm run prepublish戚篙。隨后五鲫,在所有包中運(yùn)行npm run prepare。此時(shí)岔擂,所有的依賴均已完備位喂。
發(fā)布
lerna publish // 發(fā)布所有的包。
清理
lerna clean // 刪除所有的node_modules
一些優(yōu)化
合并公共依賴
我們?cè)陂_發(fā)過程中乱灵,經(jīng)常發(fā)現(xiàn)包依賴類似塑崖。這樣,我們發(fā)現(xiàn)運(yùn)行l(wèi)erna bootstrap之后痛倚,會(huì)重復(fù)安裝依賴包规婆,這樣會(huì)造成空間的浪費(fèi)和效率的降低。為此,我們可以把同樣的依賴包在根目錄安裝一次即可抒蚜。此時(shí)掘鄙,可以使用lerna bootstrap --hoist命令,則公用的依賴嗡髓,只會(huì)在頂層目錄安裝一次操漠。
發(fā)布帶有scope公有包
帶有scope的包,需要發(fā)布時(shí)候饿这,如果是公有的包浊伙,需要在npm publish時(shí)候使用npm publish --access public。為了能夠成功publish长捧,并使用lerna流程吧黄,請(qǐng)?jiān)诿總€(gè)子包的lerna.json中加入:
"publishConfig": {
"access": "public"
}
檢測(cè)循環(huán)依賴
lerna本身內(nèi)置了檢測(cè)循環(huán)依賴的功能,如果出現(xiàn)循環(huán)依賴唆姐。會(huì)在bootstrap時(shí)候給出提示:
此時(shí)拗慨,請(qǐng)依照提示去掉循環(huán)依賴,以保證軟件包的正常運(yùn)行奉芦。
配置lerna后目錄結(jié)構(gòu)
.
├── CHANGELOG.md
├── README.md
├── docs
├── lerna.json
├── package.json
├── packages
│ ├── package-1
│ ├── ── package.json
│ ├── package-2
│ ├── ── package.json
│ ├── package-3
│ ├── ── package.json
│ ├── package-4
│ ├── ── package.json
│ └── package-5
│ ├── ── package.json
├── tslint.json
└── website
運(yùn)行腳本
"scripts": {
"bootstrap:ci": "lerna bootstrap --npm-client=npm",
"bootstrap:lerna": "lerna bootstrap -- --ignore-engines",
"release:lerna": "lerna publish --exact --skip-temp-tag --registry http://127.0.0.1:4873",
"release:beta": "lerna publish --exact --skip-temp-tag --preid=beta --npm-tag=beta --registry http://127.0.0.1:4873"
}