preface
In the early hours of October 5, 2019, Vue author Yu Yuxi published the source code of Vue3. Of course, it’s not a full Vue3 yet, but a pre-alpha version with only a few core features. Github was named VUE-Next, meaning the next vUE. Before the author published, there have been a lot of bigwigs have released some interpretation of Vue3 source code articles. However, this article does not intend to add another article to interpret the source code, but to understand and build their own Vue3 project step by step through hands-on practice from the perspective of project participants. Therefore, for best results, readers are advised to read this article while opening the terminal and follow through. You will have all the knowledge necessary to build Vue3.
Until then, it is recommended to upgrade nodeJS to a version above V10.0, which I have tested with all sorts of gut-wrenching errors. I use V10.13.0 myself.
I. Create a project
1. Create the Github repository
2. Clone the warehouse to the local PC
git clone https://github.com/gtvue/vue3.git
cd vue3
git log --oneline && tree -aI .git
Copy the code
As you can see, Github has already created and committed the following three base files.
F9fa484 (HEAD -> Master, Origin/Master, Origin /HEAD) ├── ├── f9FA484 (HEAD -> Master, Origin/Master, Origin /HEAD) ├──Copy the code
Ii. See VUe-next
1. The cloning of vue – next
cd. gitclone https://github.com/vuejs/vue-next.git
Copy the code
2. View the vue-next directory structure
cd vue-next
tree --dirsfirst -aI ".git*|.vscode|*.lock" -C -L 1
Copy the code
If you just expand the first level directory, excluding the.git start,.vscode, and.lock files, you can see that there are three main directories and eight files.
.├ ──.Circleci ├── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ├─ download.txt ├─ download.txt ├─ download.txt ├─ exclude.txt 3 directories, 8 filesCopy the code
3. Three directories
# | directories | what is it ? | how to use ? |
---|---|---|---|
1 | .circleci | Cloud continuous integration toolsCircleCI The configuration directory |
circleci.com |
2 | packages | Source directory | – |
3 | scripts | Build Script directory | – |
4. 8 files
# | files | what is it ? | how to use ? |
---|---|---|---|
1 | .prettierrc | Code formatting toolprettier Configuration file of |
prettier.io |
2 | README.md | Project introduction | – |
3 | api-extractor.json | TypeScript API extraction and analysis toolsapi-extractor Configuration file of |
api-extractor.com |
4 | jest.config.js | JavaScript Testing frameworkjest Configuration file of |
jestjs.io |
5 | lerna.json | JavaScript multi-package project management toollerna Configuration file of |
lerna.js.org |
6 | package.json | NPM configuration file | docs.npmjs.com |
7 | rollup.config.js | JavaScript module wrapperrollup Configuration file of |
rollupjs.org rollupjs.com |
8 | tsconfig.json | TypeScript The configuration file |
tslang.cn typescriptlang.org |
5. Back to initial submission
git checkout `git log --pretty=format:"%h" | tail -1`
git log --pretty=format:"'%an' commited at %cd : %s"
Copy the code
It shows that Yu Yuxi first submitted VuE-Next at 11:35 p.m. on September 19, 2018. More than a year has passed.
'Evan You' commited at Wed Sep 19 11:35:38 2018 -0400 : init (graduate from prototype)
Copy the code
Take a look at what files Utah added when it first created the project.
$ tree --dirsfirst -aI ".git*|.vscode|*.lock"- C - 1 L ├ ─ ─ packages ├ ─ ─ scripts ├ ─ ─ the prettierrc ├ ─ ─ lerna. Json ├ ─ ─ package. The json ├ ─ ─ a rollup. Config. Js └ ─ ─ tsconfig.json 2 directories, 5 filesCopy the code
Compared to the current directory structure, the files submitted for the first time are cleaner, specifically, without CircleCI, Jest, and API-Extractor. Only files related to source code and source build and package management. These are the most important parts of the whole project, and we can think of it as a startup project to develop a JavaScript library like VUe3. So these documents are very important to us. Instead of “changing history,” we might as well checkout out a new branch so we can explore as much as we want.
git checkout -b InitialCommit
Copy the code
6. package.json
The most important file to learn about a JS project is package.json, which acts as the master design diagram for the entire project. So let’s take a look at what package.json actually has when Utah commits it the first time.
Doesn’t it feel particularly refreshing? It’s so simple that it only has 4 fields. The ones we care about are scripts and devDependencies. Build scripts are pretty simple. In addition to the familiar dev and build, there is a Lint that formats all the TypeScript code in the project source code. Development dependencies are also very lean, developed in TypeScript and packaged with Rollupjs, with the most basic dependencies installed. Build scripts dev and build are still the way Utah likes to do it, putting all the build logic in two JS files, scripts/dev.js and scripts/build.js, and executing it with Node interpretation. Therefore, to understand the core build process of the entire project, you need to examine the implementation of these two files.
6.1 scripts/dev. Js
The code to start development mode is very simple, just a dozen lines of code, which is actually the executable file installed in the project (node_modules) using execA. Function execa(exefile, [arguments], [options]) returns a Promise object.
const execa = require('execa')
const { targets, fuzzyMatchTarget } = require('./utils')
const target = fuzzyMatchTarget(process.argv[2] | |'runtime-dom')
execa(
'rollup'['-wc'.'--environment'.`TARGET:${target},FORMATS:umd`] and {stdio: 'inherit'})Copy the code
Therefore, Node scripts/dev. Js is equivalent to “dev” in package.json: Rhup-wc — Environment TARGET:[TARGET],FORMATS:umd”, [TARGET] comes from the command parameter node scripts/dev.js [TARGET].
- -wc: indicates the combination of -w and -c. -c uses a configuration file
rollup.config.js
Package js, -w detects changes in source files, and automatically repackage - –environment: Sets the environment variables passed to the file, which can be in the JS file, through
process.ENV
Read, two environment variables are set here,process.ENV.TARGET = process.argv[2] || 'runtime-dom'
和process.ENV.FORMATS = umd
For more rollup parameters, see rollup command line parameters.
6.2 scripts/build. Js
There are 70 lines of code in total. To save space, only the main execution code has been captured here. Nodescripts /build.js [target] target parameter (optional) assigned to the target variable, if target is not empty, build target separately, null, Build all targets. The so-called target is the individual pacakge under the vue Packages/directory (with the same subdirectory name).
const fs = require('fs-extra')
const path = require('path')
const zlib = require('zlib')
const chalk = require('chalk')
const execa = require('execa')
const dts = require('dts-bundle')
const { targets, fuzzyMatchTarget } = require('./utils')
const target = process.argv[2];(async () = > {
if(! target) {await buildAll(targets)
checkAllSizes(targets)
} else {
await buildAll(fuzzyMatchTarget(target))
checkAllSizes(fuzzyMatchTarget(target))
}
})()
...
Copy the code
Here buildAll(targets) is a simple for loop: for (const target of targets) {await build(target)}. Therefore, the core of the build is the build(Target) function.
async function build (target) {
const pkgDir = path.resolve(`packages/${target}`)
await fs.remove(`${pkgDir}/dist`)
await execa('rollup'['-c'.'--environment'.`NODE_ENV:production,TARGET:${target}`] and {stdio: 'inherit' })
const dtsOptions = {
name: target === 'vue' ? target : `@vue/${target}`.main: `${pkgDir}/dist/packages/${target}/src/index.d.ts`.out: `${pkgDir}/dist/index.d.ts`
}
dts.bundle(dtsOptions)
console.log()
console.log(chalk.blue(chalk.bold(`generated typings at ${dtsOptions.out}`)))
await fs.remove(`${pkgDir}/dist/packages`)}Copy the code
We found that the build section is strikingly similar to scripts/dev.js. Rollup is also called using execa, but without the -w parameter, which means you don’t need to monitor changes to the source file. The environment variable process.env.node_env = production is passed, indicating the production build.
7. rollup.config.js
Rollup -c rollup.config.js rollup -c rollup.config.js rollup -c rollup.config.js rollup -c rollup.config.js Use the configuration file rollup.config.js to complete the JS build package. The configuration file itself is a JAVASCRIPT script, which means it can have a lot of logical code. In fact, the environment variables TARGET, FORMATS, and NODE_ENV mentioned earlier are also used in this file.
if(! process.env.TARGET) {throw new Error('TARGET package must be specified via --environment flag.')}// omit n lines here...
const inlineFromats = process.env.FORMATS && process.env.FORMATS.split(', ')
const packageFormats = inlineFromats || packageOptions.formats || defaultFormats
const packageConfigs = packageFormats.map(format= > createConfig(configs[format]))
if (process.env.NODE_ENV === 'production') {
packageFormats.forEach(format= > {
if (format === 'cjs') {
packageConfigs.push(createProductionConfig(format))
}
if (format === 'umd' || format === 'esm-browser') {
packageConfigs.push(createMinifiedConfig(format))
}
})
}
module.exports = packageConfigs
Copy the code
The rollup configuration file can be either an ES module or a CommonJS module, the latter being used here. It is also possible to export a single configuration object or an array of configuration objects, such as packageConfigs, in order to package multiple modules or packages at once.
Rollup configuration file See rollup cli interface – Configuration file.
8. TypeScript
Where’s TypeScript, you might ask? In fact, TypeScript is used as a rollup plug-in. It can still be found in the rollup configuration file rollup.config.js creation configuration object function createConfig().
const ts = require('rollup-plugin-typescript2')
// omit n lines here...
function createConfig(output, plugins = []) {
// omit n lines here...
const tsPlugin = ts({
check: process.env.NODE_ENV === 'production' && !hasTSChecked,
tsconfig: path.resolve(__dirname, 'tsconfig.json'),
cacheRoot: path.resolve(__dirname, 'node_modules/.rts2_cache'),
tsconfigOverride: {
compilerOptions: {
declaration: process.env.NODE_ENV === 'production' && !hasTSChecked
}
}
})
return {
plugins: [
tsPlugin,
...plugins
]
}
}
Copy the code
Json is the tsconfig.json configuration file specified by the TypeScript plugin tsPlugin. So, to see what TypeScript configuration rollup packages does, you can “step through” the tsconfig.json file. For TypeScript configuration, see tsconfig.json.
9. packages
Knowing how a project will be built and packaged, we can finally talk about our build targets, packages. We know that Vue is a multi-package (NPM package) project managed by LERna. These pacakGe are stored in the Packages directory. Each PacakGE is a subdirectory with the same package name.
tree -I *.md --dirsfirst -L 2 -C packages
Copy the code
Run the following code to try a production build:
npm i && npm run build
Copy the code
You will notice an error when packaging the Observer. Error in the source file packages/observer/SRC/autorun. Variable definitions of ts line 110. Runners = new Set() const runners:Set
= new Set() Rerun NPM run build.
npm run build
tree -I "*.md|*.json|*.ts" --dirsfirst -L 2 -C packages
Copy the code
As mentioned in section 6.2 above, running Node scripts/build.js (the build script for NPM Run Build) with no arguments will build all packages. If a package is packaged separately, you need to specify the corresponding package name as an argument. Add the following content to the “scripts” field of the package.json file in the project root directory:
"build:core": "node scripts/build.js core",
"build:observer": "node scripts/build.js observer",
"build:runtime-dom": "node scripts/build.js runtime-dom",
"build:scheduler": "node scripts/build.js scheduler",
Copy the code
Try to build separately:
Remove the dist directory already built
rm -rf packages/*/dist
npm run build:core
npm run build:observer
npm run build:runtime-dom
npm run build:scheduler
Copy the code
10. lerna
Although it has been mentioned many times that Vue is a multi-packages project managed using LERNA. But so far, even though we have completed all packages package builds, we still don’t see any use for LerNA. In fact, as we said, LERNA is used to manage multiple packages within a project and does not participate in the build. Lerna is not as complex as we thought. Here’s an official quote:
Lerna is a tool that optimizes the workflow around managing multi-package repositories with git and npm.
Lerna is a workflow optimization tool for projects that use Git and NPM to manage multiple NPM packages in the same Git repository. The implication is that it is possible to manage a multipackage repository with Git and NPM even without lerNA, but as packages become more numerous and dependent on each other, the workflow becomes extremely complex. Lerna came along to make this as easy as managing a package.
While we’re at it, let’s see what benefits LerNA brings to the VUE project. First install lerna globally:
npm install --global lerna
Copy the code
The lerna command line is available on the official website. Here are a few of the more common commands (in fact, these are almost all of lerna).
10.1 lerna init – independent / -i
Used to initialize LERNA for the first time in a new project. It creates package.json, lerna.json files and an empty package directory in the project root directory. Optionally, -i or –independent is used to set multiple Pacakges to use separate versions. The default is the same version. Of course vue-next is already initialized, so it doesn’t need to be run again, and vue-next uses the same version, which is currently 3.0.0-alpha.1. The common version is stored in lerna.json.
10.2 lerna ls
List all pacakges in the project named by the name field in package.json under each PacakGE.
$ lerna ls
info cli using localVersion of Lerna Lerna notice CLI v3.17.0 @vue/core @vue/observer @vue/ Run-time dom @vue/ Scheduler LERna Success found 4 packagesCopy the code
10.3 lerna bootstrap
This is lerna’s most important command. Used to resolve the interdependence problem between pacakages before publishing to NPM. It creates symbolic links for local package references based on dependencies in package.json files under each Pacakge, which is equivalent to nPM-link, but much simpler than linking local dependencies in each package individually. All Pacakges dependencies can now be automatically linked up with a single command run. This way we can use the package name, require or import directly in each pacakage code.
lerna bootstrap
Copy the code
Node_modules is a local pacakGE directory that stores symbolic links instead of actual pacakge files. It also saves disk space when multiple packages have the same dependency.
10.4 lerna changed
Check which pacakge changes have been made since the last release. Git-status is similar to the package dimension.
10.5 lerna diff/package?
Shows how the file has changed since the last publication. Git-diff is similar to the package dimension in that it shows where the file has changed, just like git-diff. For example, we made a change to the source code and see the following result:
Of course, we can also specify changes to a package by adding the pacakge name after the command. Note that it is not the directory name, but the package name defined by the name field in package.json, for example: @vue/ runtimedom. Readers can try it for themselves.
10.6 lerna publish
Needless to say, the multi-package release of NPM-publish.
Build your own vue3
1. Preparation
We have taken a close look at the vuE-Next build engineering. Next, we can use it to build our own VUE3. Before we do that, we will commit the previous changes to vuE-Next’s InitialCommit branch.
git add .
git commit -m "fix type error of autorun.ts and add some build scripts"
Copy the code
We now have two projects under our working directory: VUE-Next and vue3. Vue-next is our reference project, vue3 is a project we built ourselves. The JuE-Next project had two branches, the master branch and the InitialCommit branch checked out from the first commit. Of course, InitialCommit was not the original branch. We successfully fixed a BUG that changed the history, but it didn’t matter because, Our purpose is merely to be a reference, not to be incorporated into the original history. We can now switch between the Master and InitialCommit branches to refer to code in different places as needed.
For the following steps, we will use the Master branch of VUe-Next as a reference. So let’s switch to the Master branch.
git checkout master
Copy the code
2. Initialize lerNA
cd ../vue3
lerna init
Copy the code
Lerna automatically creates two configuration files, package.json and lerna.json, as well as the packages directory for all the packages of the project, which of course is now an empty directory with nothing.
tree -aI .git --dirsfirst -C
Copy the code
Commit once before proceeding to the next step.
git add . && git commit -m "Add lerna for managing packages"
Copy the code
3. Construction engineering
Copy “scripts” from package.json in vue-next root directory to package.json in vue3:
"scripts": {
"dev": "node scripts/dev.js",
"build": "node scripts/build.js",
"size-runtime": "node scripts/build.js runtime-dom -p -f esm-browser",
"size-compiler": "node scripts/build.js compiler-dom -p -f esm-browser",
"size": "yarn size-runtime && yarn size-compiler",
"lint": "prettier --write --parser typescript 'packages/**/*.ts'",
"test": "jest"
}
Copy the code
Install dependencies:
yarn add -D typescript brotli chalk execa fs-extra lint-staged minimist prettier yorkie
yarn add -D rollup rollup-plugin-alias rollup-plugin-json rollup-plugin-replace rollup-plugin-terser rollup-plugin-typescript2
yarn add -D jest ts-jest @types/jest
Copy the code
Copy the entire scripts to build directory:
cd. && cp -r vue-next/scripts vue3Copy the code
Copy the configuration file:
cp vue-next/{rollup.config.js,tsconfig.json,jest.config.js,.prettierrc} vue3
Copy the code
4. Copy the latest source code
cp -r vue-next/packages/* vue3/packages
Copy the code
5. Latest source code package
$ cdVue3 && Lerna ls LERna Notice CLI v3.16.5 @vue/compiler-core @vue/ compiler-dom@vue/reactivity@vue/run-time core @vue/runtime-dom @vue/runtime-test @vue/server-renderer vue lerna success found 8 packages $ tree -I"*.ts"- 1 - L C packages packages ├ ─ ─ the compiler - core ├ ─ ─ the compiler - dom ├ ─ ─ reactivity ├ ─ ─ the runtime - core ├ ─ ─ the runtime - dom ├ ─ ─ ├─ ├─ Template-Tempo ├─ Exdirectories, 0 filesCopy the code
You can see that there are 10 directories, but only 8 pacakge. This is because lerna recognizes a package only for directories that contain package.json files and whose “private” field is not True, which is also required for NPM. The eight directories and their package names are as follows:
directory | package |
---|---|
compiler-core | @vue/compiler-core |
compiler-dom | @vue/compiler-dom |
reactivity | @vue/reactivity |
runtime-core | @vue/runtime-core |
runtime-dom | @vue/runtime-dom |
runtime-test | @vue/runtime-test |
server-renderer | @vue/server-renderer |
vue | vue |
6. Build tests
Create symbolic links for local packages:
# rm -rf packages/*/{dist,node_modules}
lerna bootstrap
Copy the code
Start development mode:
yarn dev
Copy the code
Build all packages:
yarn build
# tree -I "*.md|*.json|*.ts|__tests__|node_modules|*.html|*.js|*.css" --dirsfirst -L 2 -C packages
Copy the code
View the size of the package file:
yarn size-runtime
yarn size-compiler
yarn size
Copy the code
Code specification inspection:
yarn lint
Copy the code
Testing:
yarn test
Copy the code
perfect ! Everything is going well.
7. Submit
git add .
git commit -m "Start vue3"
Copy the code
The End
A: congratulations! You now have your own Vue3 project. Keep contributing code to your OWN Vue3, and thankfully, you can keep up with Utah and seamlessly “reference” the latest code to improve your project.
The source address of this article: github.com/gtvue/vue3
Thank you
I spent a lot of effort writing this article. If you find it useful, please give it a thumbs up at 👍
Read the original
Wechat scan qr code to obtain the latest technology original