preface
It has been more than a month since Yu Yu Creek first published the source code for Vue3 (VUE-next). Green pen observed, just released during the National Day, there are many interpretation of Vue3 source code articles. Of course, many of the articles are just a quick introduction to the principle of responsiveness, or just a bit of upper-level guidance on where to look first and then where to look. It’s not to say that these articles aren’t valuable, but they do give you a quick, no-thinking look at some of Vue3’s most important “stuff.” But too dry is not necessarily good. Because dry food is usually the product of the author’s chewing, most of the nutrients are actually digested by the author. What is left to the reader is a seemingly juicy, but not nutritious, residue. It’s like a chop gnawed down to the bone. Such articles are usually suitable for media dissemination and are only used to quickly capture eyeballs. But for professional front-end developers who want to understand Vue3 in more detail, this is not enough.
In fact, this isn’t Qingbi’s first article about Vue3. On October 10th, five days after Vue3 was announced. Instead of reading the source code directly, Qingbi talks about the build tools and related technologies used to build Vue3 from the perspective of someone who wants to develop or participate in the Vue3 project. The article is not only to give the final “dry goods”, but the green pen in the practice of the use of methods, including the results of every line of shell command, Git skills and so on. The reader can follow the context of the article and get the same result as the black pen. This is based on qingbi’s own years of software development experience, which is that “technology is not to be seen, but to be used” **. It’s the easiest and most effective way to learn to really understand what it means when you do it yourself. Those who read obscure, complex abstract concept terms, in fact, the most afraid of is to be practical, because once encountered a practical operation of the reader, all its “jianghu forbidden art” will be seen to open, one by one crack.
But if you want to avoid detours and practice efficiently, the premise is to have a relevant article.
Build VUE3 from scratch
This article still adheres to this principle and takes you through the source code of Vue3 from a practical perspective. You can also understand it as “teach a man to fish rather than give him a fish”.
1. Preparation
In order to successfully complete the following practice. Please make sure you have the following tools installed on your computer.
- git
- Node 10 and later (LTS)
- yarn
- lerna
- typescript
Lerna and typescript use NPM for global installation. The installation method is as follows:
npm install -g lerna
npm install -g typescript
Copy the code
2. Experience Vue3 to build the next generation web application
2.1 Composition API
In fact, long before the Vue3 source code was published, Vue officials had already revealed the new interface usage of Vue3, which represents the next generation of Vue technology. This new approach is called Composition API. The corresponding classical API is also known as the Options API or option-based API.
In the classic Options API, we use a JS object with “Options” such as data and methods to define a page or component. This simple and direct approach is very user-friendly in the early stages of application, when the code and business logic are relatively simple, which is also a factor that Vue is widely embraced by developers with a low learning threshold. However, developers who have developed large Vue applications should know this. As pages become more logical, our components become long and complex. There’s a lot of logic and code that you can reuse that you can’t reuse in a very comfortable way. In Vue2, the most common way to reuse component logic and code is mixin, which is a feasible way, but it is clearly tightly coupled with the Vue framework from birth. When you try to reuse a frame-neutral generic JS function or object into a component developed in Vue2, you find that everything is very inelegant.
Driven by the need to reuse existing code more elegantly in developing large Vue applications, the Vue3 Composition API seems to be a natural and inevitable choice.
vue-composition-api-rfc
2.2 The first Composition API application
According to the official announcement, Vue3 will be officially launched in the first quarter of next year. But that doesn’t stop us from using the Composition API to develop a simple, responsive WEB application ahead of time.
And as foreplay to interpreting Vue3’s source code, we’ll actually work directly on the latest source code (you’ll see the benefits of this in a minute).
2.2.1 Cloning source code and initialization
To simplify, all commands are given in their entirety. For more details, I recommend Qingbi’s other column, Building VUE3 from Scratch, which covers the details.
# clone source code
git clone https://github.com/vuejs/vue-next.git
Go to the source directory
cd vue-next
# install dependencies
yarn
# First build
yarn build
Build internal packages soft chains
lerna bootstrap
Copy the code
In particular, lerna bootstrap is the last step, which actually creates a symbolic link (or soft link) vue and a scope directory @vue in node_modules of the project root directory.
On macOS or other Linux distributions you can view the link pointing by using the following command.
ls -l node_modules/ | grep vue
ls -l node_modules/@vue
Copy the code
You can see that symbolic links under vue and @vue point to corresponding directories under the source directory Packages /, respectively.
This way, we can directly use the individual packages in the source code before Vue3 is officially released to NPM, equivalent to using other dependencies installed from NPM. And because Vue3 is written in Typescript, all the development dependencies and configurations needed to write Typescript are already installed and provided. Therefore, we can write Typescript programs in source projects in the same way as Vue3 source code. Don’t worry, even if you’re not familiar with Typescript, you can continue reading this article.
2.2.2 Write the first Vue3 Composition API web page
In order not to pollute the Vue3 source directory structure. We can create a new branch.
git checkout -b examples
Copy the code
Create examples directories under the root directory to hold the sample code.
mkdir examples
Copy the code
The new file. / examples/composition. HTML, add the following content:
<html>
<head><title>vue3 - hello composition!</title></head>
<body>
<div id="app"><p>{{ state.text }}</p></div>
<script src=".. /node_modules/vue/dist/vue.global.js"></script>
<script>
const { createApp, reactive, onMounted } = Vue
const state = reactive({ text: 'hello world! ' })
const App = {
setup () {
onMounted((a)= > {
console.log('onMounted: hello world! ')})return { state }
}
}
createApp().mount(App, '#app')
</script>
</body>
</html>
Copy the code
Use Chrome to open the HTML file. The global variable state that we defined is accessible from the console. You can change the value of state.text as you like, and you’ll see the text displayed on the page change with the new assignment.
Congratulations to you! You have successfully written a responsive Web application using the Vue3 Composition API.
You can see the ugly component definitions that differ from the Vue2 option API. The Vue3 Composition API provides a set of API functions that, by simple combination (which is what Composition is all about), build a Vue3 responsive Web application that looks natural and comfortable. As functional programming becomes more popular, the Vue3 Composition API will become the preferred and dominant way to build the next generation of Vue applications.
3. Source code exploration
Readers of The Green Pen column “Building VUe3 from Scratch” should know that the vue3 source code is divided into several different packages, stored under the directory./ Packages /, and lerna is used to manage multiple package projects.
├─ Compiler-Core ├─ Compiler-DOM ├─ Compiler-SFC ├─ Running-Core ├─ Running-dom ├─ ├─ Shared ├─ vueCopy the code
Where compiler-SFC is the implementation of the Vue single-file component (that is, the.vue file we used in Webpack), and server-renderer is the source of server-side rendering. These two parts have not been completed as of this writing. Shared is a utility library shared by each package (equivalent to utils we usually use), which encapsulates some general functions such as whether it is an array, an object or a function. Therefore, from the perspective of understanding Vue3 source code, you can ignore it. Vue is the final Vue3 package to be released, but from the point of view of the source code, this is only the external export of the internal module, its source code is only an index.ts file, through which we can know the final Vue3 external interface. These are the API functions supported in Vue, the global object we used to create the Composition API page earlier.
To narrow our focus, the core of Vue3 consists of the following 5 packages:
reactivity
compiler-core
runtime-core
compiler-dom
runtime-dom
The first three packages, namely reactivity, Compiler-core, and Run-time core, are also the core of Vue3 core (just as the word core means). It can be said that these three packages are the lowest dependence and cornerstone for building the whole Vue3 project and even the whole Vue3 ecology. To get a better sense of what this means. I imagine a picture like this.
On a crisp fall afternoon, you yuxi carried her 13-inch macBookPro to her favorite coffee shop and ordered a latte. When I opened VSCode and started to polish it, I saw something called AngularJs. Suddenly an idea flashed through Your mind.” Wokao, this guy, go for it! I’ll get one too…” . After some hard thinking.” This particular is to do a more cool, not only for the construction of the WEB interface, but also can use the front-end familiar HTML template to build any client interface such as mobile apps. In order to achieve this effect, the page template parsing (compilation) and rendering output must be decoupled at design time. Therefore, You created a folder named compiler-core. To hold implementation will use the HTML code template compiled into the abstract syntax tree and render bridging function (bridge) used for decoupling rendering function code, the compiled template parsing, only render layer of abstraction, but also need for application level of abstraction, to run the application, and has built a second folder classmate, Named Runtime-core, it holds abstractions for creating the application and the application renderer, including abstractions for the components and nodes that make up the application. To this step, one from the HTML template (string) to build an abstract view interface has been completed, but in order to view shows the content and data binding, modify data, can be responsive to changing view content, also need to change a response data module, and classmates and opened the third folder, It is named reActivity. After technical analysis, You thinks that the most elegant way to use Proxy, a new feature of ES6, to realize data response is the most elegant way. Therefore, you decides to store and manage all responsive modules based on Proxy encapsulation in this folder. Unlike the first two packages, which are abstractions to the platform and environment, ReActivity is a figurative implementation, Just as the reactive functions used in the Hello World web page we built using the Composition API are derived from ReActivity. At this point, the underlying abstraction and responsive data model for building any user interface is complete. A platform-level implementation of Compiler-core and Run-time Core that makes no distinction between the abstract platforms is still a long way from applying this view design approach to the final product. However, rendering views for all platforms is not a small amount of work if you are familiar with platform interface development, such as IOS APP or Android APP interface development. Kexi, You only learned the Web front end. Therefore, you added two modules for rendering and application runtime implementation in the browser environment, namely compiler-DOM and run-time DOM, starting from his own familiarity. “… Unconsciously, another autumn has passed. You finally implemented that idea in a browser, but there’s still a long way to go. The next priority for You is to first implement the single file component Package and server side rendering Pacakge, so as to better develop Vue3 applications in Webpack environment and server side rendering applications that need SEO scenes.
Tips: This story is completely fictional, even a little funny ^^!
After reading this fictional story, you should have a clear understanding of the five most important modules in Vue3 currently. Finally, use a graph to summarize the relationship between them. The arrows in the picture represent dependencies. In fact, the vue package we ended up using runs in the browser, so vUE relies directly on compiler-DOM and run-time DOM. The dashed line is used for vue to Reactive dependencies because, instead of relying directly on reactivity, vue exports all of the run-time DOM exports, which in turn exports all of the Run-time core. This includes functions reactive in reactivity that create reactive objects, which in turn indirectly export reactive, the function used in the hello-world WEB application above.
4. createApp
We already know the division of labor and dependencies of the five packages that make up the core of Vue3. But how exactly do they “collaborate” with each other to create a complete WEB APP? As an example, we created the Hello World web application using the Composition API in the previous article. The following excerpt is the Javascript code (written using ES6 syntax).
const { createApp, reactive, onMounted } = Vue
const state = reactive({ text: 'hello world! ' })
const App = {
setup () {
onMounted((a)= > {
console.log('onMounted: hello world! ')})return { state }
}
}
createApp().mount(App, '#app')
Copy the code
We see the last line of code creating a Vue3 application instance using a createApp factory function, and then mounting the App root component written using the Composition API onto the Dom element with the ID App. How this process is transmitted within Vue3, or how the 5 packages we mentioned earlier collaborate to accomplish this App creation. Below is a line – by – line tracing of the blue pen to draw such a call diagram.
The areas in the figure where background colors are added are some of the areas where the packages play a key role in comparison. The yellow part is the Api exported by Vue3 in the application. The orange part is the run-time renderer created in Run-time core; The cyan part is the abstract syntax tree and DOM rendering implementation in compiler-core and Compiler-DOM for compiling template strings into rendering functions. In green are the two basic reactive apis that reActivity exports. Reactive is used to pass in a non-reactive ordinary JS object and return a reactive data object, and isReactive is used to determine whether an object is a reactive object.
5. Typescript
We know that Vue3 is written in Typescript. However, that doesn’t mean we have to learn Typescript from start to finish to understand the source code for Vue3. Javascript is known to be a weakly typed language. The benefit of this is to reduce code “noise” (syntax elements unrelated to the functionality being implemented), allowing developers to focus on the implementation of business logic and write more concise code. But there are pros and cons to everything, and when writing large software that requires greater stability and security, the flexibility of types can be a breeding ground for difficult bugs. So we have Typescript as a strongly typed language, but it’s just a superset of Javascript, which means that any legitimate Javascript code is also legitimate Typescript. At its core, Typescript adds constraints on data types (tuples, enumerations, Any, etc.) and Interface types to Javascript syntax. The real challenge in mastering Typescript is knowing how to qualify types in different scenarios. Specifically, it is variable declaration, function parameter passing, function return value, compound (Array, Set, Map, WeakSet, WeakMap) element type, interface type and type alias.
Here are some of the most common and basic Typescript types used.
// Variable declaration
let num: number = 1
let str: string = 'hello'
// Function parameter type and return value type
function sum(a: number, b: number) :number {
return a + b
}
// Compound element type
let arr: Array<number> = [1.2.3]
let set: Set<number> = new Set([1.2.2])
let map: Map<string.number> = new Map([['key1'.1], ['key2'.2]])
// Interface type
interface Point {
x: number
y: number
}
const point: Point = { x: 10, y: 20 }
// Type alias
type mathfunc = (a: number, b: number) = > number
const product: mathfunc = (a, b) = > a * b
console.log(num, str, arr, set, map, sum(1.2), product(2.3), point)
Copy the code
The above examples are relatively simple and easy to understand. One of Typesript’s most difficult types to understand, and one of Vue3’s biggest barriers to reading source code, is Generics. Generics are a mechanism for reusing type-based components (by which I mean reusable units of code, such as functions), which is somewhat abstract and can be understood simply as type variables. Usually used for functions, similar to function overloading in object-oriented programming.
Since a generic is like a type variable in Typescript, here is an example of how this variable can be defined and used.
The function identity() takes a string argument and returns itself, also a string.
function identity(arg: string) :string {
return arg
}
Copy the code
Now you don’t want the argument and return type to be fixed to string, but you want to qualify the type, so the best way to do that is to make the type mutable, or to define the type as a variable. This is called generics. After the function name, insert a pair of Angle brackets “<>” and define the variable in the Angle brackets. Then you can replace the following parameters and return types with the type variable. As follows:
function identity<T> (arg: T) :T {
return arg
}
console.log(identity<string> ('hello'))
console.log(identity<number> (100))
// The type part can also be omitted
console.log(identity('hello'))
console.log(identity(100))
Copy the code
To learn more about the usage scenarios of stereotypes, refer to the official documentation
If you understand Typescript type usage above, you should be able to read the source code for Vue3. While the features listed here aren’t all of Typescript, the rest don’t affect understanding the source code properly, and reading Vue3 source code can help you learn the most important features and best practices faster than reading and mastering all of Typescript’s features.
6. Practice understanding the core of the source code
Having said so much, finally through 3 sample code, practice summary and deepen understanding of Vue3 the most core three modules of the role, the end of the composition of this article.
6.1 reactivity
Create a new file reactivity.ts in the./examples directory and paste the following code:
import { reactive, isReactive } from '@vue/reactivity'
const content = { text: 'hello' }
const state = reactive(content)
console.log('content is reactive: ', isReactive(content))
console.log('state is reactive: ', isReactive(state))
console.log('state ', state)
content.text = 'world'
console.log('state ', state)
Copy the code
Compile and run:
tsc reactivity.ts && node reactivity.js
Copy the code
6.2 compiler – core
Create a new file compiler-core.ts in the./examples directory and paste the following code:
import { baseCompile as compile } from '@vue/compiler-core'
const template = '<p>{{ state.text }}</p>'
const { ast, code } = compile(template)
console.log('ast\n----')
console.log(ast)
console.log('code\n----')
console.log(code)
Copy the code
Compile and run:
tsc compiler-core.ts && node compiler-core.js
Copy the code
6.3 runtime – core
Create a runtime-core.ts file in the./examples directory and paste the following code:
import { createRenderer } from '@vue/runtime-core'
const patchProp = function (el: Element, key: string, nextValue: any, prevValue: any, isSVG: boolean) {}
const nodeOps = {
insert: (child: Node, parent: Node, anchor? : Node) = > {},
remove: (child: Node) = > {},
createElement: (tag: string, isSVG? :boolean) = > {},
createText: (text: string) = > {},
createComment: (text: string) = > {},
setText: (node: Text, text: string) = > {},
setElementText: (el: HTMLElement, text: string) = > {},
parentNode: (node: Node) = > {},
nextSibling: (node: Node) = > {},
querySelector: (selector: string) = >{}}const{ createApp } = createRenderer({ patchProp, ... nodeOps })console.log(createApp())
Copy the code
Compile and run:
tsc runtime-core.ts && node runtime-core.js
Copy the code
conclusion
Starting from building the first responsive Web application using Vue3 combined API, this paper successively explains the division of labor and dependence of the five most important packages constituting Vue3, and further explains the three lowest packages constituting Vue3 and building Vue3 ecology. And help readers understand the nature of Vue3 by making up an interesting story. In order to eliminate the psychological barrier of reading Vue3 source code, we add the basic knowledge of Typescript for Vue3 source code. Finally, through the hands-on writing of 3 sample code, respectively give Vue3 responsive data, template compilation and create the most important interface of the runtime application, guide readers to start debugging Vue3 core code, to really understand the core principle of Vue3.
If you are interested in Vue3 source code and the latest development, you can follow the author’s wechat, reply: vue, join the “Vue3 front-end technology exchange group”, and the author in-depth discussion and learning.
Follow the author on wechat
Build VUE3 from scratch