1、Lerna简要介绍
Lerna 是一个用来管理monorepo
项目的工具,针对使用git
和npm
管理多软件包代码仓库的工作流程进行优化,主要解决了下面的问题:
将大型代码仓库分割成多个独立版本化的 软件包(package)对于代码共享来说非常有用。但是,如果某些更改 跨越了多个代码仓库的话将变得很 麻烦 并且难以跟踪,并且,跨越多个代码仓库的测试将迅速变得非常复杂。
为了解决这些(以及许多其它)问题,某些项目会将代码仓库分割成多个软件包(package),并将每个软件包存放到独立的代码仓库中。但是,例如 Babel、 React、Angular、Ember、Meteor、Jest等项目以及许多其他项目则是在 一个代码仓库中包含了多个软件包(package)并进行开发。
Lerna发包有两种模式,本文主要讲独立模式下如何优雅的发包
2、Lerna发包的两种模式
Lerna 允许使用两种模式来管理项目:固定模式(Fixed)或独立模式(Independent)。
lerna.json是配置文件,其中"packages"字段代表需要发的包,version表示以什么形式发包
固定模式(默认)
固定模式的 Lerna 项目以单一版本来操作,所有的包都是一个版本。版本信息在lerna.json
文件的version
处。当执行lerna publish
时,如果自上次发布以来模块已经更新,那么它将被更新为您正在发布的新版本。通常来说固定模式下"packages"下所需发的包也是固定不变的,如下
// lerna.json
{
"packages": [
"packages/study-lerna-package1", // 包study-lerna-package1
"packages/study-lerna-package2" // study-lerna-package2
],
"version": "1.0.1"
}
独立模式
独立模式允许具体维护每个包的版本,包的版本有每个包的package.json的version字段维护,每次发布时,都会收到一个提示,用以说明每个更改过的包是补丁(patch)、小更改(minor)、大更改(major)还是自定义更改(custom change),通常来说没次发布的包是不固定的,需要手动维护lerna.json的packages字段
将
lerna.json
中的version
设置为independent
可以运行独立模式。
3、独立模式下如何优雅的发包
解决方案:通过脚本以命令行的形式,交互式选择要发布的包,动态修改lerna.json配置文件
// scripts/publish.js
const globby = require('globby')
const inquirer = require('inquirer')
const fs = require('fs-extra')
const handlebars = require('handlebars')
const execa = require('execa')
const cwd = process.cwd()
const getPackagePath = () => {
const packagePaths = globby.sync('../packages', {
cwd: __dirname,
onlyDirectories: true,
deep: 1,
})
return packagePaths.map((item) => item.replace('../', ''))
}
const choosePackage = async (packages) => {
const answer = await inquirer.prompt({
type: 'checkbox',
name: 'packages',
message: '选择你要发布的包',
choices: [...packages],
})
return answer
}
const reWriteLerna = (packages) => {
const jsonContent = fs.readFileSync(`${cwd}/lerna-template.txt`, 'utf-8')
const jsonResult = handlebars.compile(jsonContent)(packages)
fs.writeFileSync(`${cwd}/lerna.json`, jsonResult)
}
const publish = async () => {
const packages = getPackagePath()
const publishPackages = await choosePackage(packages)
if(publishPackages.packages.length !== 0){
reWriteLerna(publishPackages)
execa.commandSync('lerna publish', {
stdio: 'inherit',
cwd,
})
} else {
console.log("没有选择包")
}
}
publish()
// package.json
"scripts": {
"publish:independent": "node scripts/publish.js",
"publish": "lerna publish"
},
// lerna-template.txt
{
"packages": [
{{#each packages}}
{{#if @last}}
"{{this}}"
{{else}}
"{{this}}",
{{/if}}
{{/each}}
],
"version": "independent"
}
执行npm run publish:independent
,选择要发布的包,这里两个都选
选择每个包要发布的版本 最终发布成功,看到lerna.json文件修改为如下
// lerna.json
{
"packages": [
"packages/study-lerna-package1",
"packages/study-lerna-package2"
],
"version": "independent"
}
注意:需要将lerna.json
的添加到.gitignore
文件中,因为当文件修改未提交时,lerna是不允许发包的,必须提交之后才行,这里之所以不提交lerna.json是因为变化的是package字段没必要每次提交维护,造成历史记录混乱
发包成功后可以看到子包的package.json中version字段也相应的改变了,并且git log可以看到lerna已经帮你提交了,不要要手动提交