VUE 3.0 源码 script/release.js 模块发布

文件路径:VUE 3.0 源码 /script/release.js
该脚本从主函数main()函数的运行开始:
1、使用 prompt CLI提示插件,引导用户 Select release type...

? Select release type ... > patch (3.0.0) minor (3.0.0) major (3.0.0) prepatch (3.0.1-rc.0) preminor (3.1.0-rc.0) premajor (4.0.0-rc.0) prerelease (3.0.0-rc.6) custom

2、引导用户设置版本号,如果选择custom自定义版本,会提示当前的package.json version 为初始值进行编辑。
√ Select release type · custom ? Input custom version ? 3.0.0-rc.5

3、使用 semver 插件验证版本有效性。semver 全称Semantic Version 版本命名规范,可以比较两个版本号的大小、验证某个版本号是否合法、提取版本号,例如从“=v1.2.1”体取出"1.2.1"等功能。
4、再次确认版本
? Releasing v3.0.0-rc.6. Confirm? (y/N) ? false

5、发布前做单元测试
6、更新 package.json 版本 & 内部依赖模块版本
7、从git元数据生成变更日志,判断有修改信息,进行code提交
8、Pushing to GitHub...
源码注释
/** * minimist 轻量级的命令行参数解析引擎 * process.argv.slice(2) 对应 执行命令参数位置(即第3个起始位,对等下例中"-x 3 -y 4 -n 5 -abc --beep=boop foo bar baz"这部分数据) 实例如下: * node example/parse.js -x 3 -y 4 -n 5 -abc --beep=boop foo bar baz * args 结果为:{ *_: [ 'foo', 'bar', 'baz' ], *x: 3, *y: 4, *n: 5, *a: true, *b: true, *c: true, *beep: 'boop' *} */ const args = require('minimist')(process.argv.slice(2)) /** nodejs模块——fs模块:fs模块用于对系统文件及目录进行读写操作 */ const fs = require('fs') /* nodejs模块:提供文件路径相关api */ const path = require('path') /* 控制台日志标注样式 */ const chalk = require('chalk') /** * Semantic Version 版本命名规范,提供以下等功能 * 1. 比较两个版本号的大小 * 2. 验证某个版本号是否合法 * 3. 提取版本号,例如从“=v1.2.1”体取出"1.2.1" * 4.分析版本号是否属于某个范围或符合一系列条件 */ const semver = require('semver') /* 获取跟目录 package.json version信息 */ const currentVersion = require('../package.json').version /** * enquirer: 用户友好、直观且易于创建的时尚CLI提示。 * CLI(command-line interface,命令行界面)是指可在用户提示符下键入可执行指令的界面 */ const { prompt } = require('enquirer') /* 用于执行外部程序 例如:git */ const execa = require('execa')/** * preId * prerelease('1.2.3-alpha.1') -> ['alpha', 1] */ const preId = args.preid || semver.prerelease(currentVersion)[0] || 'alpha' const isDryRun = args.dry const skipTests = args.skipTests const skipBuild = args.skipBuild /** * 获取模块名称列表 * [ *'compiler-core', *'compiler-dom', *'compiler-sfc', *'compiler-ssr', *'reactivity', *'runtime-core', *'runtime-dom', *'runtime-test', *'server-renderer', *'shared', *'size-check', *'template-explorer', *'vue' * ] */ const packages = fs .readdirSync(path.resolve(__dirname, '../packages')) .filter(p => !p.endsWith('.ts') && !p.startsWith('.'))const skippedPackages = []const versionIncrements = [ 'patch', 'minor', 'major', 'prepatch', 'preminor', 'premajor', 'prerelease' ]/** * inc 版本升级 * semver.inc('1.2.3', 'prerelease', 'beta') // 1.2.4-beta.0 */ const inc = i => semver.inc(currentVersion, i, preId) // bin: 执行.bin下指令的 函数 const bin = name => path.resolve(__dirname, '../node_modules/.bin/' + name) // run: 通过execa执行外部程序的函数封装 const run = (bin, args, opts = {}) => execa(bin, args, { stdio: 'inherit', ...opts }) // dryRun: 打印执行程序的相关信息,不会实际执行 const dryRun = (bin, args, opts = {}) => console.log(chalk.blue(`[dryrun] ${bin} ${args.join(' ')}`), opts) // runIfNotDry: 通过 isDryRun 变量 决定run函数 const runIfNotDry = isDryRun ? dryRun : run // getPkgRoot: 获取指定模块 pkg 的具体路径 const getPkgRoot = pkg => path.resolve(__dirname, '../packages/' + pkg) // step: 封装 chalk 输出日志 const step = msg => console.log(chalk.cyan(msg))// 主函数即入口函数 async function main() { let targetVersion = args._[0] if (!targetVersion) { // no explicit version, offer suggestions /** * prompt 函数,它接受一个“问题”对象或一组问题对象,并返回一个包含用户响应的对象。 * @param questions {Array|Object} * @returns {Promise} ? Select release type ... > patch (3.0.0) minor (3.0.0) major (3.0.0) prepatch (3.0.1-rc.0) preminor (3.1.0-rc.0) premajor (4.0.0-rc.0) prerelease (3.0.0-rc.6) custom */ const { release } = await prompt({ type: 'select', name: 'release', message: 'Select release type', choices: versionIncrements.map(i => `${i} (${inc(i)})`).concat(['custom']) })if (release === 'custom') { /** * 自定义版本,会提示当前的package.json version 为初始值进行编辑。 √ Select release type · custom ? Input custom version ? 3.0.0-rc.5 */ targetVersion = (await prompt({ type: 'input', name: 'version', message: 'Input custom version', initial: currentVersion })).version } else { /** * 'prerelease (3.0.0-rc.6)'.match(/\((.*)\)/)[1] * 返回:'3.0.0-rc.6' */targetVersion = release.match(/\((.*)\)/)[1] } }/** * 验证版本有效性 * semver.valid('a.b.c') // null * semver.valid('1.2.3') // '1.2.3' */ if (!semver.valid(targetVersion)) { throw new Error(`invalid target version: ${targetVersion}`) }/** * 二次确认版本信息 * ? Releasing v3.0.0-rc.6. Confirm? (y/N) ? false */ const { yes } = await prompt({ type: 'confirm', name: 'yes', message: `Releasing v${targetVersion}. Confirm?` })if (!yes) { return }// run tests before release // 发布前单元测试 step('\nRunning tests...') if (!skipTests && !isDryRun) { await run(bin('jest'), ['--clearCache']) await run('yarn', ['test']) } else { console.log(`(skipped)`) }// update all package versions and inter-dependencies // 更新 package.json 版本 & 内部依赖模块版本 step('\nUpdating cross dependencies...') updateVersions(targetVersion)// build all packages with types step('\nBuilding all packages...') if (!skipBuild && !isDryRun) { await run('yarn', ['build', '--release']) // test generated dts files step('\nVerifying type declarations...') await run('yarn', ['test-dts-only']) } else { console.log(`(skipped)`) }/** * generate changelog * 从git元数据生成变更日志 * conventional-changelog -p angular -i CHANGELOG.md -s */ await run(`yarn`, ['changelog'])const { stdout } = await run('git', ['diff'], { stdio: 'pipe' }) // 判断有修改信息,进行code提交 if (stdout) { step('\nCommitting changes...') await runIfNotDry('git', ['add', '-A']) await runIfNotDry('git', ['commit', '-m', `release: v${targetVersion}`]) } else { console.log('No changes to commit.') }// publish packages step('\nPublishing packages...') for (const pkg of packages) { await publishPackage(pkg, targetVersion, runIfNotDry) }// push to GitHub step('\nPushing to GitHub...') await runIfNotDry('git', ['tag', `v${targetVersion}`]) await runIfNotDry('git', ['push', 'origin', `refs/tags/v${targetVersion}`]) await runIfNotDry('git', ['push'])if (isDryRun) { console.log(`\nDry run finished - run git diff to see package changes.`) }if (skippedPackages.length) { console.log( chalk.yellow( `The following packages are skipped and NOT published:\n- ${skippedPackages.join( '\n- ' )}` ) ) } console.log() }function updateVersions(version) { // 1. update root package.json updatePackage(path.resolve(__dirname, '..'), version) // 2. update all packages packages.forEach(p => updatePackage(getPkgRoot(p), version)) }function updatePackage(pkgRoot, version) { const pkgPath = path.resolve(pkgRoot, 'package.json') const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8')) pkg.version = version updateDeps(pkg, 'dependencies', version) updateDeps(pkg, 'peerDependencies', version) fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n') }/** * 更新内部模块依赖包版本 * "dependencies": { *"@vue/shared": "3.0.0-rc.5", *"@vue/compiler-dom": "3.0.0-rc.5", *"@vue/runtime-dom": "3.0.0-rc.5" * }, */ function updateDeps(pkg, depType, version) { const deps = pkg[depType] if (!deps) return Object.keys(deps).forEach(dep => { // 判断 "@vue/shared" => shared 是 packages 内部模块时再修改版本 if ( dep === 'vue' || (dep.startsWith('@vue') && packages.includes(dep.replace(/^@vue\//, ''))) ) { console.log( chalk.yellow(`${pkg.name} -> ${depType} -> ${dep}@${version}`) ) deps[dep] = version } }) }// 软件包发布到 npm 注册表,该注册表用于在全球范围内分发软件包。 async function publishPackage(pkgName, version, runIfNotDry) { if (skippedPackages.includes(pkgName)) { return } const pkgRoot = getPkgRoot(pkgName) const pkgPath = path.resolve(pkgRoot, 'package.json') const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8')) if (pkg.private) { return }// for now (alpha/beta phase), every package except "vue" can be published as // `latest`, whereas "vue" will be published under the "next" tag. const releaseTag = pkgName === 'vue' ? 'next' : null// TODO use inferred release channel after official 3.0 release // const releaseTag = semver.prerelease(version)[0] || nullstep(`Publishing ${pkgName}...`) try { await runIfNotDry( 'yarn', [ 'publish', '--new-version', version, ...(releaseTag ? ['--tag', releaseTag] : []), '--access', 'public' ], { cwd: pkgRoot, stdio: 'pipe' } ) console.log(chalk.green(`Successfully published ${pkgName}@${version}`)) } catch (e) { if (e.stderr.match(/previously published/)) { console.log(chalk.red(`Skipping already published: ${pkgName}`)) } else { throw e } } }main().catch(err => { console.error(err) })

如果您对 “前端源码” 情有独钟,可微信关注前端源码解析公众号,内容持续更新中!
【VUE 3.0 源码 script/release.js 模块发布】当前 VUE3.0 源码正在解析中,欢迎捧场!
VUE 3.0 源码 script/release.js 模块发布
文章图片

~

    推荐阅读