若川源码解读源地址:https://juejin.cn/post/6997943192851054606
感谢若川哥组织的阅读源码活动,收获很大,想加入的小伙伴看过来: 公告
1. 相关依赖包
const args = require('minimist')(process.argv.slice(2))
const fs = require('fs')
const path = require('path')
const chalk = require('chalk')
const semver = require('semver')
const currentVersion = require('../package.json').version
const {
prompt } = require('enquirer')
const execa = require('execa')
minimist
minimist轻量级的命令行参数解析引擎
解析过程中,minimist会依次匹配不同的模式,从long options到short options,匹配之后再进行相应的解析工作。
其中process.argv的第一和第二个元素是Node可执行文件和被执行JavaScript文件的完全限定的文件系统路径,无论你是否这样输入他们。
$ node example/parse.js -a beep -b boop
{
_: [], a: 'beep', b: 'boop' }
$ node example/parse.js -x 3 -y 4 -n5 -abc --beep=boop foo bar baz
{
_: [ 'foo', 'bar', 'baz' ],
x: 3,
y: 4,
n: 5,
a: true,
b: true,
c: true,
beep: 'boop' }
chalk
chalk 包的作用是修改控制台中字符串的样式,包括:
- 字体样式(加粗、隐藏等)
- 字体颜色
- 背景颜色
semver
语义化版本的nodejs实现,用于版本校验比较等。
semver 定义了两种概念:
- 版本是指例如 0.4.1、1.2.7、1.2.4-beta.0 这样表示包的特定版本的字符串。
- 范围则是对满足特定规则的版本的一种表示,例如 1.2.3-2.3.4、1.x、^0.2、>1.4.
在这两种概念上可以进行很多种计算,例如比较两个版本的大小、判断一个版本是否满足一个范围、判断一个版本是否比范围中的任何版本都大等。
版本格式:主版本号.次版本号.修订号,版本号递增规则如下:
主版本号:当你做了不兼容的 API 修改,
次版本号:当你做了向下兼容的功能性新增,
修订号:当你做了向下兼容的问题修正。
先行版本号及版本编译信息可以加到“主版本号.次版本号.修订号”的后面,作为延伸。
enquirer
命令行交互工具,例如发布时选择相关版本号
execa
execa是可以调用shell和本地外部程序的javascript封装。会启动子进程执行。支持多操作系统,包括windows。如果父进程退出,则生成的全部子进程都被杀死。
2. 主要流程解读
运行下面的命令 yarn release --dry
,会控制台会显示发布的整套流程
// 执行测试用例
Running tests...
(skipped)
// 更新依赖版本
Updating cross dependencies...
// 打包编译所有包
Building all packages...
// 生成CHANGELOG.md文件描述
$ conventional-changelog -p angular -i CHANGELOG.md -s
// commit代码
Committing changes...
// 发布包
Publishing packages...
Publishing compiler-core...
// 提交到github
Pushing to GitHub...
3. main函数
3.1 取版本号
// 根据上文 mini 这句代码意思是 yarn run release 3.2.4
// 取到参数 3.2.4
let targetVersion = args._[0]
// 如果不存在版本号就手动选择相关版本
if (!targetVersion) {
// no explicit version, offer suggestions
const {
release } = await prompt({
type: 'select',
name: 'release',
message: 'Select release type',
choices: versionIncrements.map(i => `${
i} (${
inc(i)})`).concat(['custom'])
})
if (release === 'custom') {
targetVersion = (
await prompt({
type: 'input',
name: 'version',
message: 'Input custom version',
initial: currentVersion
})
).version
} else {
targetVersion = release.match(/((.*))/)[1]
}
}
// 校验版本是否符合规范
if (!semver.valid(targetVersion)) {
throw new Error(`invalid target version: ${
targetVersion}`)
}
// 确认要 release
const {
yes } = await prompt({
type: 'confirm',
name: