文件路径:VUE3.0源码/script/release.js脚本从运行main函数main()函数开始:1.使用提示CLI提示插件并引导用户选择发布类型...?选择发布类型...>补丁(3.0.0)次要(3.0.0)主要(3.0.0)预补丁(3.0.1-rc.0)preminor(3.1.0-rc.0)premajor(4.0.0)-rc.0)预发布(3.0.0-rc.6)自定义2。引导用户设置版本号。如果选择custom自定义版本,会提示编辑当前package.json版本作为初始值。√选择发布类型·自定义?输入自定义版本?3.0.0-rc.53。使用semver插件验证版本有效性。semver的全称是SemanticVersion版本命名约定。它可以比较两个版本号的大小,验证某个版本号是否合法,并提取版本号,比如从“=v1.2.1”的正文中提取“1.2.1”。4.再次确认版本?发布v3.0.0-rc.6。确认?(y/N)?false5.发布前做单元测试6.更新package.json版本&内部依赖模块版本7.从git元数据Log生成变更,判断有修改信息,提交代码8.推送到github...sourcecodecomment/***minimist轻量级命令行参数解析引擎*process.argv.slice(2)对应执行命令参数的位置(即第3个起始位相当于"-x3-y4-n5-abc--beep=boopfoobarbaz"在下面的例子中)示例如下:*nodeexample/parse.js-x3-y4-n5-abc--beep=boopfoobarbaz*args结果是:{*_:['foo','bar','baz'],*x:3,*y:4,*n:5,*a:true,*b:true,*c:true,*beep:'boop'*}*/constargs=require('minimist')(process.argv.slice(2))/**nodejs模块——fs模块:使用了fs模块读写系统文件和目录*/constfs=require('fs')/*nodejs模块:提供文件路径相关api*/constpath=require('path')/*Consolelogannotationstyle*/constchalk=require('chalk')/***SemanticVersion版本命名约定,提供以下功能*1.比较两个版本号的大小*2.验证a版本号是否合法*3.提取版本号,例如从“=v1.2.1”正文中提取“1.2.1”*4.分析版本号是否属于某个范围或满足一个一系列条件*/constsemver=require('semver')/*从目录中获取package.json版本信息*/constcurrentVersion=require('../package.json').version/***enquirer:用户友好、直观且易于创建时尚的CLI提示*CLI(command-lineinterface,命令行界面)是指可以在用户提示符下键入可执行指令的界面*/const{prompt}=require('enquirer')/*用于执行外部程序如:git*/constexeca=require('execa')/***preId*prerelease('1.2.3-alpha.1')->['alpha',1]*/constpreId=args.preid||semver.prerelease(当前版本)[0]||'alpha'constisDryRun=args.dryconstskipTests=args.skipTestsconstskipBuild=args.skipBuild/***获取模块名称列表*[*'compiler-core',*'compiler-dom',*'compiler-sfc',*'compiler-ssr',*'reactivity',*'runtime-core',*'runtime-dom',*'runtime-test',*'server-renderer',*'shared',*'size-检查',*'template-explorer',*'vue'*]*/constpackages=fs.readdirSync(path.resolve(__dirname,'../packages')).filter(p=>!p.endsWith('.ts')&&!p.startsWith('.'))constskippedPackages=[]constversionIncrements=['patch','minor','major','prepatch','preminor','premajor','prerelease']/***inc版本升级*semver.inc('1.2.3','prerelease','beta')//1.2.4-beta.0*/constinc=i=>semver.inc(currentVersion,i,preId)//bin:执行.bin下命令的功能constbin=name=>path.resolve(__dirname,'../node_modules/.bin/'+name)//run:通过execa执行外部程序的函数包construn=(bin,args,opts={})=>execa(bin,args,{stdio:'inherit',...opts})//dryRun:打印执行程序的相关信息,不会真正执行constdryRun=(bin,args,opts={})=>console.log(chalk.blue(`[dryrun]${bin}${args.join('')}`),opts)//runIfNotDry:确定通过isDryRun变量=isDryRun运行函数construnIfNotDry?dryRun:run//getPkgRoot:获取指定模块pkg的具体路径constgetPkgRoot=pkg=>path.resolve(__dirname,'../packages/'+pkg)//step:封装chalk输出日志conststep=msg=>console.log(chalk.cyan(msg))//main函数是入口函数asyncfunctionmain(){lettargetVersion=args._[0]if(!targetVersion){//没有明确的版本,offersuggestions/***提示函数接受一个“问题”对象或问题对象数组,并返回一个包含用户回答的对象*@param问题{Array|Object}*@returns{Promise}?选择发布类型...>补丁(3.0.0)次要(3.0.0)主要(3.0.0)预补丁(3.0.1-rc.0)预发布(3.1.0-rc.0)预发布(4.0.0)-rc.0)prerelease(3.0.0-rc.6)custom*/const{release}=awaitprompt({type:'select',name:'release',message:'选择发布类型',choices:versionIncrements.map(i=>`${i}(${inc(i)})`).concat(['custom'])})if(release==='custom'){/***自定义版本,会提示当前package.json版本编辑为初始值。√选择发布类型自定义?输入自定义版本?3.0.0-rc.5*/targetVersion=(awaitprompt({type:'input',name:'version',message:'Inputcustomversion',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)){thrownewError(`invalidtargetversion:${targetVersion}`)}/***两个版本v3.0.0-rc.6.确认?(y/N)?false*/const{yes}=awaitprompt({type:'confirm',name:'yes',message:`Releasingv${targetVersion}.Confirm?`})if(!yes){return}//发布前运行测试//发布前单元测试step('\nRunningtests...')if(!skipTests&&!isDryRun){awaitrun(bin('jest'),['--clearCache'])awaitrun('yarn',['test'])}else{console.log(`(skipped)`)}//更新所有包versionsandinter-dependencies//updatepackage.jsonversion&internaldependenciesstep('\nUpdatingcrossdependencies...')updateVersions(targetVersion)//使用类型构建所有包step('\nBuildingallpackages...')if(!skipBuild&&!isDryRun){awaitrun('yarn',['build','--release'])//测试生成的dts文件step('\nVerifyingtypedeclarations...')awaitrun('yarn',['test-dts-only'])}else{console.log(`(skipped)`)}/***生成变更日志*从git元数据生成变更日志*conventional-changelog-pangular-iCHANGELOG。md-s*/awaitrun(`yarn`,['changelog'])const{stdout}=awaitrun('git',['diff'],{stdio:'pipe'})//判断有修改信息,提交代码','-m','重新lease:v${targetVersion}`])}else{console.log('Nochangestocommit.')}//发布包step('\nPublishingpackages...')for(constpkgofpackages){awaitpublishPackage(pkg,targetVersion,runIfNotDry)}//推送到GitHubstep('\nPushingtoGitHub...')awaitrunIfNotDry('git',['tag',`v${targetVersion}`])awaitrunIfNotDry('git',['push','origin',`refs/tags/v${targetVersion}`])awaitrunIfNotDry('git',['push'])if(isDryRun){console.log(`\nDry运行完成-运行gitdiff以查看包更改。`)}if(skippedPackages.length){console.log(chalk.yellow(`以下包被跳过且未发布:\n-${skippedPackages.join('\n-')}`))}console.log()}functionupdateVersions(version){//1.更新根package.jsonupdatePackage(path.resolve(__dirname,'..'),version)//2.更新所有包packages.forEach(p=>updatePackage(getPkgRoot(p),version))}functionupdatePackage(pkgRoot,version){constpkgPath=path.resolve(pkgRoot,'package.json')constpkg=JSON.parse(fs.readFileSync(pkgPath,'utf-8'))pkg.version=versionupdateDeps(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"*},*/functionupdateDeps(pkg,depType,version){constdeps=pkg[depType]if(!deps)returnObject.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注册中心,此注册表用于在全球范围内分发包异步函数publishPackage(pkgName,version,runIfNotDry){if(skippedPackages.includes(pkgName)){return}constpkgRoot=getPkgRoot(pkgName)constpkgPath=path.resolve(pkgRoot,'package.json')constpkg=JSON。parse(fs.readFileSync(pkgPath,'utf-8'))if(pkg.private){return}//现在(alpha/beta阶段),除“vue”之外的每个包都可以发布为//`latest`,而“vue”将在“下一个”标签下发布。constreleaseTag=pkgName==='vue'?'next':null//TODO在正式3.0发布后使用推断的发布渠道//constreleaseTag=semver.prerelease(version)[0]||nullstep(`Publishing${pkgName}...`)try{awaitrunIfNotDry('yarn',['publish','--new-version',version,...(releaseTag?['--tag',releaseTag]:[]),'--access','public'],{cwd:pkgRoot,stdio:'pipe'})console.log(chalk.green(`Succe成功发布${pkgName}@${version}`))}catch(e){if(e.stderr.match(/previouslypublished/)){console.log(chalk.red(`跳过已发布:${pkgName}`))}else{throwe}}}main().catch(err=>{console.error(err)})如果你对“前端源码”情有独钟,可以按照微信前端源码解析公众号,内容持续更新中!目前VUE3.0源码正在解析中,欢迎加入!~
