This is the fourth day of my participation in the August Text Challenge.More challenges in August
First of all, thank you for the reading of the source code
preface
The main purpose of this article is to learn the vuE-Next release process. After studying this article, you will gain three skills
1. Nodejs debugging skills 2. Know vuE-Next release process 3. Improve the release process for your own projectsCopy the code
The preparatory work
Clone project to local vue – next, and ensure that the node version 10 + yarn 1 x, the source code in/vue – next/blob/master/scripts/release.
After open the project, in the node can see release is executed in the scripts/vue – next/blob/master/scripts/the js
How to debug nodeJS can see the previous article you may not know vue-devTools open file principle
Release process – A picture is worth a thousand words
Source code parsing – line by line analysis
Lines 1-30, mainly introducing some packages and declaring some variables.
Minimist parsing parameters
Semvernpm version management tool
Enquirer interactive command line tool
Preid releases a good version, if there is use custom, if not use semver management.
IsDryRun Is in debugging state
Packages Packages that need to be packaged
SkippedPackages need to be skipped
VersionIncrements Which method to modify the version number
const args = require('minimist')(process.argv.slice(2))
const fs = require('fs')
const path = require('path')
const chalk = require('chalk')
const semver = require('semver')
// The semantic versioner for npm
const currentVersion = require('.. /package.json').version
const { prompt } = require('enquirer')
/ / interaction
const execa = require('execa')
const preId =
args.preid ||
(semver.prerelease(currentVersion) && semver.prerelease(currentVersion)[0])
const isDryRun = args.dry
const skipTests = args.skipTests
const skipBuild = args.skipBuild
const packages = fs
.readdirSync(path.resolve(__dirname, '.. /packages'))
.filter(p= >! p.endsWith('.ts') && !p.startsWith('. '))
const skippedPackages = []
const versionIncrements = [
'patch'.'minor'.'major'. (preId ? ['prepatch'.'preminor'.'premajor'.'prerelease'] : [])]Copy the code
Lines 32-40 some tool methods
Inc accepts an additional identifier string argument that takes the value of the additional string as a pre-release identifier for example:
Inc (' 1.2.3 ', 'prerelease', 'beta') / / '1 - beta. 0'Copy the code
Bin Command execution
The run execa perform
```js const inc = i => semver.inc(currentVersion, i, preId) const bin = name => path.resolve(__dirname, '.. /node_modules/.bin/' + name) const run = (bin, args, opts = {}) => execa(bin, args, { stdio: 'inherit', ... opts }) const dryRun = (bin, args, opts = {}) => console.log(chalk.blue(`[dryrun] ${bin} ${args.join(' ')}`), opts) const runIfNotDry = isDryRun ? dryRun : run const getPkgRoot = pkg => path.resolve(__dirname, '.. /packages/' + pkg) const step = msg => console.log(chalk.cyan(msg))Copy the code
The Main function
43-80 What version do you choose to release
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}`)}const { yes } = await prompt({
type: 'confirm'.name: 'yes'.message: `Releasing v${targetVersion}. Confirm? `
})
if(! yes) {return
}
Copy the code
TargetVersion targetVersion
NPM run Release 1.1.2 args._ => [1.1.2]Copy the code
For details, see Minimist
If there is no target version then an interaction is triggered as follows:
VersionIncrements is defined above, if custom custom version number is selected, then the input continues:
.
After the input, Semver verifies whether the version number meets the requirements of NPM.
If it passes, it will start asking for confirmation, whether to publish.
Running tests...
81-90 Perform tests
// run tests before release
step('\nRunning tests... ')
if(! skipTests && ! isDryRun) {await run(bin('jest'),'--clearCache'])
await run('yarn'['test'.'--bail'])}else {
console.log(`(skipped)`)}Copy the code
This passage is very simple. Whether to skip tests or just print debugging.
The run function
const run = (bin, args, opts = {}) = >
execa(bin, args, { stdio: 'inherit'. opts })Copy the code
Run (bin(‘jest’), [‘–clearCache’]) => run jest –clearCache on the command line.
Run (‘yarn’, [‘test’, ‘– Bail ‘]) => Equivalent to YARN test — Bail. Yarn is pre-installed, so bin is not required.
91-94 Updated version number
// update all package versions and inter-dependencies
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)`)}Copy the code
This section starts by updating the version numbers for Packages and internals. If update, then we need to figure out updateVersions
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')}function updateDeps(pkg, depType, version) {
const deps = pkg[depType]
if(! deps)return
Object.keys(deps).forEach(dep= > {
if (
dep === 'vue' ||
(dep.startsWith('@vue') && packages.includes(dep.replace(/^@vue\//.' ')))) {console.log(
chalk.yellow(`${pkg.name} -> ${depType} -> ${dep}@${version}`)
)
deps[dep] = version
}
})
}
Copy the code
UpdateVersions, updatePackage, updateDeps
UpdateVersions: Set a breakpoint in packages. ForEach (p => updatePackage(getPkgRoot(p), version)).
This is when we see that Packages are the following packages and then iterate through the updatePackage.
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')}Copy the code
Update the root version of dependencies, and then update the versions of dependencies, peerDependencies. The diagram below:
94-104 started to build
// 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)`)}Copy the code
Build Two commands are run yarn build –release YARN test-dts-only
106-116 Generate and submit a log
// generate changelog
await run(`yarn`['changelog'])
const { stdout } = await run('git'['diff'] and {stdio: 'pipe' })
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.')}Copy the code
Yarn Changelog is executed in this part
Then execute git diff to commit if any changes are made. Commit comment is: release: VXXX.
123-142 line tag&push
// 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- '
)}`))}Copy the code
This part contains simple tag, then push, and finally if there is a skipped package, the yellow font will be printed. After the release of the end ~
conclusion
By looking at the source code above, you can learn what the release process of a good open source project looks like.
There are a number of tools available to assist publishing. For example:
-
Commit from HusKY and Lint-staged commits using ESLint and others to verify that the commit will pass detection. If it does not pass detection, the commit will not succeed, thus standardizes team coding
-
Use Git-CZ to standardize the submission format and so on