Writing an article is not easy, click a like brother focus on Vue source code sharing, the article is divided into vernacular version and source version, vernacular version to help understand the working principle, source version to help understand internal details, let us study together based on Vue version [2.5.17]

If you think the layout is ugly, please click the link below or pull to the following public account can also be

Compile – source version of the main process from new instances to the end of Compile

Compile the content of many, today to a warm up, first do not study Compile internal details, but to record

Start from creating a new instance, and finish compile, the approximate external process of which does not involve compile’s internal process

Or we’re going to look at how compile is generated, right

Note, don’t read this article if you’re not ready

Be careful. It can get confusing. Don’t get dizzy

Ok, the text begins

First, Vue is called when we create an instance through Vue

So start with the Vue function

function Vue() {/ /... vm.$mount(vm.$options.el);
}
Copy the code

Then the rest of the internal processing can be ignored and go directly to vm.$mount, where compilation starts

Go ahead and find this function

Vue.prototype.$mount = function(el) {    



    var options = this.$options;

   

    if(! options.render) { var tpl= options.template; // Get the template stringifTPL = document.querySelector(TPL).innerhtml; TPL = document.querySelector(TPL). }ifVar ref = compileToFunctions(TPL, {},this); // Each component has its own render options.render = ref.render options.staticRenderFns =ref. }} // Execute render, generate the DOM, mount the DOM, ignore the discussion herereturn mount.call(this, el)
};
Copy the code

Compile produces the render function from the template template

So at this point, the whole process is done, because render is already generated here

We observed that

In the function above, there are three main things it does

1 Obtain the template template

Depending on the parameters you pass in, get the various template templates

I think you can see everything here, depending on the DOM, or depending on the selectors

2 generate render

Pass template to compileToFunctions

Render and staticRenderFns can be generated

It looks pretty simple, just one compileToFunctions, but let me tell you, this function is not going to be easy to create, it’s going to be very convoluted, very convoluted, and yes, that’s what we’re going to be looking at

But the process doesn’t seem to be helping, right? But if you read the source code, it might help you sort it out a little bit

Once again, I admire the brain circuits of Utah

3 save render

Save to vm.$options for later calls

Here’s the history of compileToFunctions

Mind you, it’s a lot of twists and turns. Brace yourself

First I go to compileToFunctions and see the code below

var refThe $1= createCompiler(); // compileToFunctions returns the render function and staticRenderFns var compileToFunctions = refThe $1.compileToFunctions;
Copy the code

So I know

CompileToFunctions are returned by the createCompiler execution!!

Continue locating createCompiler


createCompiler

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

Oh, my God, another function. Don’t get dizzy, man

Let’s be clear about two things

CreateCompiler is created by createCompilerCreator

CreateCompilerCreator passes a function called baseCompile

baseCompile

The baseCompile is the guy that generates render

Parse, optimize, generate

But that’s not what I’m talking about today, these three things, each of them is huge

I’m going to skip this, but baseCompile is important, it’s going to be called later, so remember that

Then, yes, we come across a function createCompilerCreator. Locate it!


createCompilerCreator

function createCompilerCreator(baseCompile) {    



    return function() {// merges options and calls baseCompilefunctionThe compile (template) {/ / baseCompile is step on incoming, here to perform get {ast, render, statickRenderFn} var compiled = baseCompile (template);return compiled

        }        

        return{// compile execution returns the string render compile returned by baseCompile: Compile, // To create a layer of cache closure and the closure saves compile // we get a function called compileToFunctions that packages the render string in the function: createCompileToFunctionFn(compile) } } }Copy the code

After this function is executed, a function is returned

Obviously, the returned function is assigned directly to the createCompiler described above

What is going on in this function that is returned to createCompiler?

Generate a function compile

There is a function compile, which is used to compile

Call baseCompile and return the baseCompile result

BaseCompile, which we highlighted earlier, is the big guy that generates render

If you forget it, you can go back and see it

{render, staticRenderFns}

Return compileToFunctions and compile

The two functions that are returned do roughly the same thing

All to execute the internal compile above

But why separate one compileToFunctions?

Remember our compileToFunctions from the beginning

That’s what we’re going to explore in vm.$mount

It is he that generates render and staticRenderFns

If you look at the internal compile, you can see that it returns when it’s finished

{ render, staticRenderFns }

CompileToFunctions vm.$mount compileToFunctions

Why don’t compileToFunctions just compile!!

Because do template cache!!

As you can see, I’m not directly going to compileToFunctions = internal compile

But pass the createCompileToFunctionFn the internal the compile

Yes createCompileToFunctionFn is cached

To avoid compiling each instance many times, we cache it, and then fetch the cache directly after compiling it once

createCompileToFunctionFn

Looking at the internal source code, the cached code is highlighted in red

functionCreateCompileToFunctionFn (compile) {/ / as a cache, prevent recompiling / / every time the template string as the key, Render and staticRenderFns var cache = object.create (null);return functioncompileToFunctions(template, options, vm) { var key = template; // If there is a cache, just fetch the result from the cacheif (cache[key]) returnCompile var compiled = compile(template, options); Var res = {/ / compiled. The render is a string, it is necessary to render into Function: new Function (compiled. Render) staticRenderFns: compiled.staticRenderFns.map(function(code) {                

                return  new Function(code, fnGenErrors)

            });
        };        



        return (cache[key] = res)

    }
}

Copy the code

Bonus: Render string becomes executable function

var res = {    

    render: new Function(compiled.render) ,    

    staticRenderFns: compiled.staticRenderFns.map(function(code) {        

        return new Function(code, fnGenErrors)

    });
};
Copy the code

This code renders the Render string executable function, since the render generated form is a string that should be called later, such as a function

So we use new Function() to convert to a Function

StaticRenderFns is the same thing, except it’s an array that needs to be iterated over and converted to functions one by one

What did he do with his cache

Use a cache closure variable

The template for the key

Render is generated as value

When the instance is first rendered, it is stored in the cache

When the instance is rendered parsed a second time, it is fetched directly from the cache

When will the instance be parsed a second time?

For example, page A goes to page B, and page B goes to page A.

An instance of page A would normally need to be parsed twice, but not with caching


ideas

In other words, compileToFunctions are called baseCompile!

But compileToFunctions are two-wave wrapped baseCompile

The first wave is wrapped in an internal compile function in createCompilerCreator

The function inside is going to be

Merge public options and custom options, but the code has been omitted,

Another is to implement baseCompile

The second wave is wrapped in createCompileToFunctions for caching purposes