Standing on the shoulders of giants to see VUE, vUE design and implementation from Huo Chunyang. The author explains the underlying vuE3 implementation step by step in the form of questions. The idea is very clever, here will be the main logic in the book series, which is also my own record after reading, I hope that through this form can communicate with everyone to learn.
The opening
The vue. js template compiler is used to compile templates into rendering functions, which are divided into three main steps:
- Analyze the template and parse it into template AST
- Convert the template AST to a JavaScript AST that describes the rendering function
- Generate the rendering function code according to the JavaScript AST
The first step of the Parser process is to construct a lexical parser from a finite-state automaton, which is the Whiler loop traversal template. Such as
The second step, transform, transforms the template AST into a JavaScript AST. When accessing the nodes of the AST, the AST is traversed in depth optimization mode. Access to nodes is divided into entry and exit stages, and only the current node is processed in the exit node stage. To achieve the AST conversion. There are two other points to note here, one is the plug-in mechanism and the other is context. To understand the access and replacement operations of a decoupled node, the node can be wrapped into separate transformation functions that can be registered as arrays that are iterated over and executed using callbacks that take the array parameters. Context objects maintain information about the current state of the program, the parent node currently accessed, and the location index of the node currently accessed.
Third, turn the JavaScript AST into a function of render
15.1. Compiler for template DSL
The process by which a compiler translates source code into object code is called compilation. The complete compilation process includes:
Vue template compiler
- By encapsulating the parse function to complete the lexical analysis and syntax analysis of the template, the template AST is obtained.
- Once you have a template AST, you can perform semantic analysis on it and transform it, such as checking whether v-IF instruction exists in V-else instruction and analyzing whether it is static or constant, etc
- Transform from template AST to JavaScript AST is completed by encapsulating transform function.
- Generate render function according to JavaScriptAST through generate function;
function compiler(template) {
const templateAST = parser(template) / / template AST
const jsAST = transform(templateAST) // javascript AST
const code = generate(jsAST) // Code generation
}
Copy the code
15.2 Implementation principle and state machine of Parser
The input parameter to the parser is the string template. The parser reads the characters in the string template one by one and slices the whole string into tokens according to certain rules.
How the parser cuts the template is based on finite state automata: in a finite number of states, the parser automatically migrates between different states as characters are entered.
The state machine is divided into six states: initial state, label start state, label name state, text state, end label state, and end label name state.
According to these six state machines, the template is traversed, the switch determines which state is hit, and then the output format is processed
const tokens = tokenzie(`<p>Vue</p>`)
/ / /
// { type: 'tag', name: 'p' },
// { type: 'text', content: 'Vue' },
// { type: 'textEnd', name: 'p' }
// ]
Copy the code
Finally, with finite automatic state machines, we can parse templates into tokens that can then be used to build an AST.
15.3. Construct the AST
HTML is a markup language with a very fixed format and naturally nested tag elements that form parent-child relationships. So the AST results in a tree deconstruction that describes HTML by constructing json data formats with specific attribute values.
Iterate through the Token list to maintain a stack elementStack, and when a start tag is pushed onto the stack, an end tag is encountered to pop the current stack element. Whiler cycles through tokens until all tokens have been scanned and an AST tree is generated.
Code-for-vue-3-book /code-15.1.html at master · HcySunYang/code-for-vue-3-book
15.4. AST transformation and plug-in system
15.4.1. Node Access
To transform an AST, you need to access every node of the AST so that you can modify, replace, or delete a specific point.
function traverseNode(ast) {
const currentNode = ast
const children = currentNode.children
if (children) {
for (let i = 0; i < children.length; i++) { traverseNode(children[i]) } } }Copy the code
The replacement logic is decoupled through callback functions to prevent traverseNode logic from being too bloated. Pass in the context and inject the nodeTransforms array method.
function traverseNode(ast, context) {
const currentNode = ast
const transforms = context.nodeTransforms
for (let i = 0; i < transforms.length; i++) {
transforms[i](currentNode, context)
}
const children = currentNode.children
if (children) {
for (let i = 0; i < children.length; i++) { traverseNode(children[i]) } } }Copy the code
15.4.2. Convert context and node operations
Context is the “global variable” of a program in a certain scope. Context can be regarded as the context data during the AST conversion function. All AST conversion functions can share nodes through the context. Setting the value of the context ensures that the information stored in the context object is correct in the recursive transformation.
function traverseNode(ast, context) {
context.currentNode = ast
const transforms = context.nodeTransforms
for (let i = 0; i < transforms.length; i++) {
transforms[i](context.currentNode, context)
}
const children = context.currentNode.children
if (children) {
for (let i = 0; i < children.length; i++) { context.parent = context.currentNode context.childIndex = i traverseNode(children[i], context) } } }Copy the code
This allows you to add, replace, or delete nodes.
function transform(ast) {
const context = {
currentNode : null.childIndex: 0.parent: null.// Replace the node
replaceNode(node) {
context.parent.children[context.childIndex] = node
context.currentNode = node
},
// Delete a node
removeNode() {
if (context.parent) {
context.parent.children.splice(context.childIndex, 1)
context.currentNode = null}},nodeTransforms: [
transformElement,
transformText
]
}
traverseNode(ast, context)
}
Copy the code
15.4.3 Entry and Exit
In the process of transforming AST nodes, it is often necessary to decide how to transform the current node according to the situation of the child nodes, which requires that the transformation operation of the parent node must wait until all its child nodes have been transformed.
The access to the node is divided into two stages, namely the entry stage and then the exit stage. When the transformation function is in the entry stage, the heart enters the parent node and then enters the child node. When the transition function is in the exit phase, it exits the child node first and then the parent node. In this way, as soon as we exit the node stage and process the node we are currently visiting, we can ensure that all its children are processed.
Methods are pushed into exitFns while iterating through the methods by setting an array of exitFns. Finally, the while loop executes the exitFns function, using queue first-in, last-out logic.
15.5. Convert template AST to Javascript AST
Vue
Template
Need to convert to
function render() {
return h('div', {
h('p'.'Vue'),
h('p'.'Template')})}Copy the code
The AST generated from the template in the previous section needs to be converted to Javascript AST, and the description of Javascript AST,
const FunctionDeclNode = {
type: 'FunctionDecl'.// indicates that the node is declared as a function
id: {
type: 'Identifier'.name: 'render' // name Specifies the name used to store identifiers
},
params: [].// Render function parameters
body: [{type: 'ReturnStatement'.return: null}}]Copy the code
Code-for-vue-3-book /code-15.5.html at master · HcySunYang/code-for-vue-3-book
15.6 code generation
Convert the generated JavaScript to render function format
Code-for-vue-3-book /code-15.6.html at master · HcySunYang/code-for-vue-3-book