🚢 preface
This is the 29th day of my participation in Gwen Challenge
I vaguely remember when we were writing vue, there was always a template at the top. Most of the time, we don’t care enough to realize what
is.
In this article, we will take you to understand what happens behind the template compilation.
Let’s learn more about template compilation: 🚋🚋🚋
First, 📑 template compilation
Use render instead of template in vue components
Template is a template. Templates are the most commonly used part of VUE development, the principle most associated with the use of VUE. It’s not HTML, it has instructions, it has interpolation, it has JS expressions, so what is it? Let’s look at an example.
To define a component in VUE, you typically use the Template template string to define a component. Such as:
Vue.component('heading', {template:`xxx`
})
Copy the code
In general, templates are defined in this way. Also, during program compilation, the template compiles the string type of template into the render function.
However, in complex cases where the template function may not be available, consider using the Render function to define a component directly. Such as:
Vue.component('heading', {render: function(createElement){
return createElement(
'h' + this.level, //tag props
[ //children
createElement('a', {attrs: {name:'headerId'.href:The '#' + 'headerId'}},'this is a tag'])}})Copy the code
As above, we can also define a component by using a render function.
2. Summary of template compilation
After looking at the above example, let’s make a summary ✨
- Template is a template. This template will compile to
render
Function, whererender
The delta function is calledwith
Syntax. - Process: template →
render
The function –vnode
→ Component rendering and updating process. vue
Components can be usedrender
Function instead oftemplate
。React
Always userender
, there is no template (here only for knowledge supplement, not to explain).
✏️ Feel the inner beauty of template compilation
1
(1) Examples show 🌰
The with syntax is an important part of template compilation. Here is an example to show how the with syntax differs from normal syntax.
When executing a program without using the with syntax:
const obj = {a: 100.b: 200}
console.log(obj.a)
console.log(obj.b)
console.log(obj.c) //undefined
Copy the code
When executing a program using the with syntax:
// use with to change the search for free variables in {}
// find the free variable in {} as an attribute of obj
with(obj){
console.log(a)
console.log(b)
console.log(c) // Error!!
}
Copy the code
(2) Knowledge point induction
The with syntax is the same as the with syntax.
with
The syntax changes{}
内Lookup rules for free variables, as aobj
Property to find;- If at the moment
{}
I can’t find a matchobj
Property, an error is reported; with
Be careful with it, it breaksScope ruleAnd will make itLegibility gets worse.
📈 Compile the template
1. Compile template chatter
As mentioned earlier, a template is not HTML, it has instructions, interpolation, JS expressions, it can achieve judgment, can also achieve loop.
Why is a template not HTML?
Think about it, if you were writing a program, could you write a judgment or loop in HTML? The answer is not natural.
So HTML is just a static tagging language, it shows you what you write, it has no way of implementing logic, or doing loops and judgments.
Therefore, for the front-end browser, only JS can realize various logical functions such as judgment and loop.
Therefore, the template must be converted to some KIND of JS code before it is run. The process of converting this template into JS code is called compiling the template.
So how does this template work? Let’s look at the process of compiling templates.
2. Process of compiling templates
(1) Initialize an NPM environment
Start by creating a new file called vue-template-complier-demo. Then initialize an NPM environment with the following command line:
npm init -y
Copy the code
(2) Install the compiler
NPM installs the template compiler. The command line is as follows:
npm install vue-template-compiler --save
Copy the code
(3) Create new files
Initialize a new index.js file in the root directory and introduce vue-template-compiler. The code is as follows:
Vue / / in the template - the compiler
const compiler = require('vue-template-compiler')
/ / compile
const res = compiler.compile(template)
console.log(res.render)
Copy the code
Let’s take a look at how interpolation, expressions, properties, and dynamic properties are compiled in templates.
(4) Understand abbreviated functions
The following vUE source abbreviation function first understand, will be used in the following explanation.
// Find the meaning of the abbreviation function in vue source code
function installRenderHelpers (target) {
target._c = createElement;
target._o = markOnce;
target._n = toNumber;
target._s = toString;
target._l = renderList;
target._t = renderSlot;
target._q = looseEqual;
target._i = looseIndexOf;
target._m = renderStatic;
target._f = resolveFilter;
target._k = checkKeyCodes;
target._b = bindObjectProps;
target._v = createTextVNode;
target._e = createEmptyVNode;
target._u = resolveScopedSlots;
target._g = bindObjectListeners;
target._d = bindDynamicKeys;
target._p = prependModifier;
}
Copy the code
(5) Compile interpolation
Vue / / in the template - the compiler
const compiler = require('vue-template-compiler')
/ / the interpolation
const template = `<p>{{message}}</p>`
// with(this){return createElement('p',[createTextVNode(toString(message))])}
// h -> vnode
// createElement -> vnode
/ / compile
const res = compiler.compile(template)
console.log(res.render)
Copy the code
Compile the above content and print the following result:
As you can see in the figure above, the template of the interpolation type is eventually compiled into a with statement with arguments pointing to this.
And, as you can see, there’s a _c, _V, _S. So what are these elements?
This is the vue source abbreviation function mentioned in point 4 above. _c corresponds to createElement, _v corresponds to createTextVNode, and _s corresponds to toString.
With (this){return _c(‘p’,[_v(_s(message))])}, With (this){return createElement(‘p’,[createTextVNode(toString(message))])}
The compiler creates a p element, and then the p element has no children, so it creates its text node message, and message exists as a string, so toString.
As an added bonus, createElement is what we call an h function that returns a virtual DOM node.
The above is an interpolation template compilation process, with a few more examples to familiarize you.
(6) Compile the expression
Vue / / in the template - the compiler
const compiler = require('vue-template-compiler')
/ / expression
const template = `<p>{{flag ? message : 'no message found'}}</p>`
// with(this){return _c('p',[_v(_s(flag ? message : 'no message found'))])}
/ / compile
const res = compiler.compile(template)
console.log(res.render)
Copy the code
Compile the above content and print the following result:
According to the above interpolation analysis method, we analyze the expression template compilation process.
With (this){return _c(‘p’,[_v(_s(flag? Message: ‘no message found’))])} with(this){return createElement(‘p’,[createTextVnode(toString(flag? ‘no message found’)]}.
We create a p element, and then the P element has no children, so we create a text node, and finally toString the contents of the ternary expression.
(7) Compile attributes and dynamic attributes
Vue / / in the template - the compiler
const compiler = require('vue-template-compiler')
// Attributes and dynamic attributes
const template = `
`
// with(this){return _c('div',
// {staticClass:"container",attrs:{"id":"div1"}},
/ / /
// _c('img',{attrs:{"src":imgUrl}})])}
/ / compile
const res = compiler.compile(template)
console.log(res.render)
Copy the code
Compile the above content and print the following result:
Based on the above analysis method, we will analyze the template compilation process of attributes and dynamic attributes.
Properties and dynamic properties are compiled to return a virtual DOM node. Similarly, by querying the vue source abbreviation function, With the (this) {return _c (‘ div ‘{staticClass: “container”, attrs: {” id “:” div1 “}}, [_c (” img “, {attrs: {” SRC “: imgUrl}})])} is equal to the final results with(this){return The createElement method (‘ div ‘{staticClass: “container”, attrs: {” id “:” div1 “}}, [the createElement method (” img “, {attrs: {” SRC “: imgUrl}})])}.
We can see that the returned vNode contains the class name container. The div has an ID selector, which is an attribute of the div and is represented by attrs.
After the outermost layer, there’s another layer inside, IMG. Img can think of it as a tag just like div, so the img element is created first because IMG binds a specific value, just as div binds an ID selector. So after creating the img value, continue attrs to pass the img bound value.
(8) Compilation conditions
/ / conditions
const template = `
A
B
`
// with(this){return _c('div',[(flag === 'a')?_c('p',[_v("A")]):_c('p',[_v("B")])])}
Copy the code
Compile the above content and print the following result:
Based on the above analysis method, we will analyze the conditional template compilation process.
For conditions, a div element is created first, and then template compilation splits v-if and V-else into a trinary expression.
(9) Compile loop
/ / loop
const template = `
- {{item.title}}
`
// with(this){return _c('ul',_l((list),function(item){return _c('li',{key:item.id},[_v(_s(item.title))])}),0)}
Copy the code
Compile the above content and print the following result:
Based on the above analysis method, let’s analyze the template compilation process of the loop.
For the above loop, we first create a UL element, and then the query _L abbreviation function we know is renderList, so the list list will be compiled by the RenderList function.
The final rendered item is passed as an argument to the function, and the corresponding Li list element is returned side by side.
(10) Compile event
/ / event
const template = ` `
// with(this){return _c('button',{on:{"click":clickHandler}},[_v("submit")])}
Copy the code
Compile the above content and print the following result:
Based on the above analysis method, we will analyze the template compilation process of the event.
For events, a button element is first created, after which @click (V-on :click) is compiled into ON :{“click”:clickHandler}. And finally, _v, createTextVNode. Create a Submit text node and submit the click content to it.
(11) Compile the V-Model
// v-model
const template = `<input type="text" v-model="name">`
// Look at the input event
// with(this){return _c('input',{directives:[{name:"model",rawName:"v-model",value:(name),expression:"name"}],attrs:{"type":"text"},domProps: {"value":(name)},on:{"input":function($event){if($event.target.composing)return; name=$event.target.value}}})}
Copy the code
Compile the above content and print the following result:
According to the above analysis method, we analyze the template compilation process of bidirectional binding V-Model.
For the V-Model, the main thing to look at is the input event. The name and value syntax sugars are bound behind the V-model. Attrs is then used to create an attribute of type text.
Finally, the input event is bound to $event. Finally, the value of name is equivalent to $event.target.value, and the data is bound in both directions.
3. Summary of template compilation
With that in mind, let’s summarize template compilation:
(1) From render function to vnode
The template is compiled with a render function, which returns a vNode;
(2) Vnode to patch and DIff
Based on vNode, patch and DIff are executed.
(3) Template compilation tools
In normal development, we can use webpack, vue-loader and other build tools to compile templates in the development environment.
4. 🔑 component rendering/update process
1. Getting to know component rendering/updating
With that said, let’s talk about a topic that has a lot to do with compiling templates: the component rendering/update process.
What are the principles behind a component that starts with rendering onto the page and then changes data to trigger updates (data-driven views), and what are the key points to understand?
In fact, the component is template-compiled before rendering, and the template is compiled into the Render function.
Then there’s listening to the data, which is reactive data. Vue’s responsiveness keeps data up to date by calling Object.defineProperty() to listen for getter and setter methods.
After listening on the data, execute the render function to generate the VNode.
After the step of vnode (vDOM), patch(elem,vnode) and Patch (vnode,newVnode) will be compared.
As for the interpretation of responsivity principle and VDOM, if necessary, you can check my first two articles to learn, and I will not expand the details here ~
2. Component rendering/update process
Component rendering and update process mainly goes through the following three steps: initial rendering process → update process → asynchronous rendering.
The following three steps will be explained one by one.
(1) Initial rendering process
The initial rendering process, how the component was first rendered, how the template was rendered onto the page. Specifically, there are three steps:
- The parse template is
render
Functions; - Trigger reactive, listening
data
attributegetter
和setter
; - perform
render
Function, generatevnode
,patch(elem,vnode)
。
Here are three steps to explain one by one.
1) Parse template as render function
In development environments, parsing templates into render functions is usually handled by the vue-loader plug-in. There is also the case where users directly import vuejs files using CDN for native code exercises, in which case the render function to parse the template is run in the browser environment.
So with that little knowledge, let’s look at this step.
The render template is the render function.
2) Trigger response
After compiling the template, the render function is available and we start listening for the data property.
Listen for the data property, and that’s when we need to trigger reactive, rendering data.
So how do you render the data at this stage?
At this stage we need to execute the render function, which fires the getter method because the data is not updated, just rendered. Setter methods are only manipulated when rendering.
3) Execute render function to generate VNode
Finally, when the data is rendered, the render function generated in the first step is executed, and then the virtual DOM node vnode is generated, followed by patch(elem,vnode).
(2) Update process
1) Details of update process
The update process is how the component is updated after data is modified.
At this stage, the data is modified and the setter is fired (note: the data is already being listened for in the getter).
After the setter is triggered, the render function is re-executed and newVnode is generated. Finally, the diff comparison of patch(vnode, newVnode) is performed.
2) Complete the flow chart
Next we use a flow chart to complete the rendering and update process.
(3) Asynchronous rendering
After rendering and updating, our program may have multiple programs loading at the same time, which involves an asynchronous rendering problem.
Asynchronous rendering problem, we use $nextTick as an example to explain.
Suppose we now want to implement a feature that prints out the number of items in a list when we click a button. That’s probably what most of us would do at this point.
<template>
<div id="app">
<! Select DOM element from node -->
<ul ref="ul1">
<li v-for="(item, index) in list" :key="index">
{{item}}
</li>
</ul>
<button @click="addItem">To add a</button>
</div>
</template>
<script>
export default {
name: 'app'.data() {
return {
list: ['a'.'b'.'c']}},methods: {
addItem() {
this.list.push(`The ${Date.now()}`)
this.list.push(`The ${Date.now()}`)
this.list.push(`The ${Date.now()}`)
// Get the DOM element
const ulElem = this.$refs.ul1
console.log( ulElem.childNodes.length )
}
}
}
</script>
Copy the code
The browser displays the following information:
As you’ve noticed, browsers don’t print the way we think they do. When the list on the page displays 6 items, the console prints only 3 items. When 9 items are displayed, the console directly prints only 6 items.
So why is that?
In fact, the moment we click, the data changes, but DOM doesn’t render immediately. So by the time we’re done, we’re getting the same element that triggered it, not adding anything new to it.
What we want is for DOM rendering to be triggered immediately after the click and the latest value to be retrieved. That’s where nextTick comes in. The specific code is as follows:
<script>
export default {
name: 'app'.data() {
return {
list: ['a'.'b'.'c']}},methods: {
addItem() {
this.list.push(`The ${Date.now()}`)
this.list.push(`The ${Date.now()}`)
this.list.push(`The ${Date.now()}`)
$nextTick (); $nextTick ();
// The NextTick function is triggered only once after the data has been modified several times and the DOM has been rendered
// 2. Data changes will be integrated during page rendering
this.$nextTick(() = > {
// Get the DOM element
const ulElem = this.$refs.ul1
console.log( ulElem.childNodes.length )
})
}
}
}
</script>
Copy the code
We do this by nesting a $nextTick function on top of the code that gets the DOM element. During this process, when we click through, the value of data changes, and $nextTick waits for the DOM to be fully rendered before calling back.
The final browser print looks like this:
So, in other words, $nextTick updates the view once again by summarizing changes to the data.
This reduces the number of DOM operations and greatly improves performance.
3, summary
After the above series of explanations, we can divide the content into the following two main points:
- Understand the relationship between rendering and responsiveness, rendering and template compilation, and rendering and VDOM.
- Understand the component rendering/updating process: first rendering process → update process → asynchronous rendering.
V. ✔️ Conclusion
From template compilation to component rendering and updating, we learned the whole process behind the template. I believe that through the study of this article, we have a deeper understanding of template compilation.
So much for template compilation! If you don’t understand or the article is wrong, please leave a message in the comment section or add my wechat to communicate
- Pay attention to the public number Monday laboratory, the first time to pay attention to learning dry goods, more interesting columns for you to unlock ~
- If this article is helpful, please like it and follow it
- See you next time! 🥂 🥂 🥂