I wanted to understand the virtual DOM, but I didn’t know where it came from, so I figured out how to compile templates. Because of their own ability, can not handwritten implementation, just a simple process to clear the template compilation, and then paste some key code, you can go to the source code to find the key place. I read it directly in vue. Js instead of downloading THE NPM of Vue to find each module, so please kindly advise me if you have any misunderstanding.

Get HTML (template)

Vue has two runtime compilations, one for the Runtime version of the NPM runtime and one for the run-time version of vuejs introduced by the browser.

The runtime – only:

Compile.vue file into js with vue-loader, then render it with render function, then compile it into the format required by render function when packaging, no need to compile on client side:

Render function () : render function (); render function () : render function ();

new Vue({
  render: h => h(App),
}).$mount('#app')

//error
You are using the runtime-only build of Vue where the template compiler is not available.
 Either pre-compile the templates into render functions, or use the compiler-included build.
Copy the code

runtime-compile

The template string is compiled into JS for rendering, which is compiled directly on the client side at runtime, so the el is usually passed to initialize the vue, or template or mount can be used. Render >template>el>mount Render > template > el > mount Render >template>el>mount

Vue. Js introduced with render:

new Vue({ el: '#app', data(){ return { msg: 'msg' } }, render(h){ return h('div', { attrs:{"id":"app"}, staticClass:"test", staticStyle:{"background":"red"} }, <div id="app" class="test" style="background: red; >is render</div>Copy the code

The getOuterHTML function can be found in vue.js:

template = getOuterHTML(el);

function getOuterHTML (el) {
    if (el.outerHTML) {
      return el.outerHTML
    } else {
      var container = document.createElement('div');
      container.appendChild(el.cloneNode(true));
      return container.innerHTML
    }
}
Copy the code

This is the HTML that gets the el element passed in, and you can use this function yourself to see the result, which is essentially the string of the entire tag.

2. Transform into AST

An AST is called an abstract syntax tree, and all languages can be converted into an AST. Once you have the HTML content, the first step is to convert the HTML to an AST, which can be used for various compilation extensions. Vue just generates the render function.

Var ast = parse(template.trim(), options); Then print the result:

You can expand them all to see the content. Vue2 is mainly matched one by one with re’s. You can search startTagOpen to see the main re’s.

Vue3 has been changed to packages > Compiler-core > SRC > parse.ts to see if it is parsed character by character. The resulting fields have been changed a bit, but the final result is almost the same.

tips

{{}} is the syntax mustache, which is used in many libraries.

ParseHTML function

The main function of parsing, through the front side and stack data structure of the start tag, the end tag, text, comments, etc., respectively for different types of elements to add different types, used to mark different node types.

Optimize function

This function is called after the generation:

if (options.optimize ! == false) { optimize(ast, options); }Copy the code

Static node (static node) and static root node (staticRoot) add tags. Check that staticRoot is false whenever it is not purely static. The purpose is to optimize patch performance. Static patch can be directly copied without comparison.

Generate the render function

With ast, generate the render function via the generate function:

var createCompiler = createCompilerCreator(function baseCompile ( template, options ) { var ast = parse(template.trim(), options); if (options.optimize ! == false) { optimize(ast, options); } var code = generate(ast, options); return { ast: ast, render: code.render, staticRenderFns: code.staticRenderFns } });Copy the code

The render function is just a string with the with syntax:

with(this){ return _c('div',{attrs:{"id":"app"}}, [_c('p',{staticClass:"test",staticStyle:{"background":"red"}}, [_v (" is "+ _s (MSG) + _s (MSG))]), _v (" "), _c (' div ', [_v (" ss")])])}Copy the code

Tips: With syntax is used to handle data variables such as _s(MSG)

let obj = {name: 'wade'}
with(obj){
    console.log(name) //wade
}
Copy the code

Vue simply passes vue instance this to assign data directly to the virtual DOM when it is generated.

createFunction

If you have a string, you can use the new Function to execute it.

  function createFunction (code, errors) {
    try {
      return new Function(code)
    } catch (err) {
      errors.push({ err: err, code: code });
      return noop
    }
  }
Copy the code

_c _s _v

The render function doesn’t just use these three, but a brief introduction to these three:

  • _c createElement Creates an element
  • _v createTextVNode Creates text
  • _s toString puts data json.stringify or String

There are other functions that you can search for installRenderHelpers, which have various handlers.

genElement

Render (v-for, v-if, v-if, v-if, v-for, v-if) Template, slot, Component, element are evaluated and processed differently.

Generate virtual DOM

With the render function, the call generates the virtual DOM (vNode) at mount. Vue. Prototype. The mount. Vue. Prototype. The mount. Vue.prototype.mount calls mountComponent.

MountComponent function

BeforeMount, mounted, Watcher, but with vm._update(vm._render(), hydrating).

Vue.prototype._render

_render is basically calling render and generating the virtual DOM:

vnode = render.call(vm._renderProxy, vm.$createElement);
Copy the code

You can print the vNode directly to see the structure of the virtual DOM:

It’s a little bit different than the algorithms that are used to analyze virtual DOM diff, for example, props, vue is actually data, but it’s just a different use of the fields, the principle is the same.

If you look closely, you’ll see that the virtual DOM is very much like the AST, but with a few more properties. Make it clear that ast is a syntactic attribute that describes the language itself. It can describe dom, JS, CSS, Java, and other languages. It is not allowed to add non-existent attributes. The virtual DOM is a self-defined data structure used to describe the DOM, and you can add the required attributes at will.

Generate the real DOM

The actual DOM is generated using vue.prototype. _update, which contains a few lines of code:

var prevVnode = vm._vnode; var restoreActiveInstance = setActiveInstance(vm); vm._vnode = vnode; // Vue.prototype.__patch__ is injected in entry points // based on the rendering backend used. if (! prevVnode) { // initial render vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */); } else { // updates vm.$el = vm.__patch__(prevVnode, vnode); }Copy the code
  • PrevVnode is oldVnode
  • Vnode is the latest virtual DOM
  • vm._vnode = vnode; The new cache, the next update is oldVnode
  • ! PrevVnode initial Render prevVnode initial Render prevVnode initial Render prevVnode
  • Vue. Prototype. Patch = inBrowser? patch : noop;

Calling _update will generate the actual DOM, which is the core of the PATCH function and dom diff.

The following is a summary of the vue template compilation process:

  • Get HTML (Template)
  • Into the ast
  • Generating the render function
  • Generating the virtual DOM
  • Generating a real DOM

Template compilation steps are generally like this, it is best to compare with a few core functions, and then their own to vue.js source code inside look. Best of course is to pull the Vue NPM package down to see, the division will be more detailed.

It’s easier to sort out the process of compiling vue templates, then look at dependency collection, see when to trigger a refresh, and then learn dom diff.

Finally, the process is clear, but the most core implementation steps I do not fully understand, that is, I can not write, after all, reading the code is much easier than typing the code.

Welcome to the Coding personal Note subscription number