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 toolsCircleCIThe 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 toolprettierConfiguration file of prettier.io
2 README.md Project introduction
3 api-extractor.json TypeScript API extraction and analysis toolsapi-extractorConfiguration file of api-extractor.com
4 jest.config.js JavaScript Testing frameworkjestConfiguration file of jestjs.io
5 lerna.json JavaScript multi-package project management toollernaConfiguration file of lerna.js.org
6 package.json NPM configuration file docs.npmjs.com
7 rollup.config.js JavaScript module wrapperrollupConfiguration file of rollupjs.org rollupjs.com
8 tsconfig.json TypeScriptThe 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 filerollup.config.jsPackage 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, throughprocess.ENVRead, 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