directory

  1. Principles of Template Compilation
  2. Parse the parser
  3. Transform processing
  4. Generate generates the renderer
  5. conclusion
  • template code -> ast -> Optimized AST after processing -> Rendering function
  • The compiler is going to betemplate codeConverted intoRendering function
  • Input: view template, output: render function

1. Principle of compiling templates

// Compile the function
// The input value is view template
const compile = (template) = > {
  // Render function
  return (observed, dom) = > {
  	// Render process}}Copy the code

The short answer is

  • Enter: View template
  • Output: Render function

It can be broken down into three small steps

  • Parse template string -> AST(Abstract Syntax Treee) Abstract Syntax tree
  • Transform conversion tags such as v-bind V-if V-for conversion
  • Generate AST -> render function
// Template string -> AST(Abstract Syntax Treee) Abstract Syntax tree
let ast = parse(template)
// Conversion processing such as V-bind v-if V-for conversion, (with marking static nodes, AST tree optimization processing, improve performance)
ast = transfer(ast)
// AST -> render function
return generator(ast)
Copy the code

You can get a feel for this with the online version of VueTemplateExplorer

vue-next-template-explorer.netlify.com/

Compiler function parsing

Second, Parse

The way a parser works is a series of regular matches.

Such as:

Matching of tag attributes

  • class=”title”
  • class=’title’
  • class=title
const attr = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)=("([^"]*)"|'([^']*)'|([^\s"'=<>`]+)/

"class=abc".match(attr);
// output
(6) ["class=abc"."class"."abc".undefined.undefined."abc".index: 0.input: "class=abc".groups: undefined]

"class='abc'".match(attr);
// output
(6) ["class='abc'"."class"."'abc'".undefined."abc".undefined.index: 0.input: "class='abc'".groups: undefined]

Copy the code

We’ll talk more about that when we implement it. You can refer to the article.

AST parser in action

So for our project we could write it like this

// <input v-model="message"/>
// <button @click='click'>{{message}}</button>
// The transformed AST syntax tree
const parse = template= > ({
    children: [{
            tag: 'input'.props: {
                name: 'v-model'.exp: {
                    content: 'message'}},}, {tag: 'button'.props: {
                name: '@click'.exp: {
                    content: 'message'}},content:'{{message}}'}],})Copy the code

3. Transform processing

The previous section did the abstract syntax tree, and this is where the special transformation to the Vue3 template takes place.

For example, vFor and vOn

In Vue, the three will be carefully divided into two levels for processing

  • Compile -core Core compilation logic

    • AST-Parser

    • Basic types are resolved v-for and V-ON

Compile-dom compile logic for the browser

  • v-html

  • v-model

  • v-clock

const transfer = ast= > ({
    children: [{
            tag: 'input'.props: {
                name: 'model'.exp: {
                    content: 'message'}},}, {tag: 'button'.props: {
                name: 'click'.exp: {
                    content: 'message'}},children: [{
                content: {
                    content: 'message'},}]}],})Copy the code

Generate Generate renderer

The generator simply generates the rendering function from the transformed AST syntax tree. Of course you can render different results for the same syntax tree. For example, if you want to render a button or an SVG block, it is up to you. This is called a custom renderer. Here we simply write a fixed Dom renderer placeholder. When I get to the next implementation, I’m unpacking.

const generator = ast= > (observed, dom) = > {
    // re-render
    let input = dom.querySelector('input')
    if(! input) { input =document.createElement('input')
        input.setAttribute('value', observed.message)
        input.addEventListener('keyup'.function () {
            observed.message = this.value
        })
        dom.appendChild(input)
    }
    let button = dom.querySelector('button')
    if(! button) {console.log('create button')
        button = document.createElement('button')
        button.addEventListener('click'.() = > {
            return config.methods.click.apply(observed)
        })
        dom.appendChild(button)
    }
    button.innerText = observed.message
}
Copy the code

reference

  • Vue compiler principles

conclusion

  • template code -> ast -> Optimized AST after processing -> Rendering function
  • The compiler is going to betemplate codeConverted intoRendering function
  • Input: view template, output: render function