入口文件
上章了解到入口web入口文件是entry-runtime-with-compiler ,那么这个文件做了什么呢?
主要代码为导入依赖文件,实现mount函数和导出Vue。导入和导出暂不做了解,主要了解了解mount的实现
一些校验
// 挂载的节点不能直接在body或者html上面
if (el === document.body || el === document.documentElement) {
process.env.NODE_ENV !== 'production' && warn(
`Do not mount Vue to <html> or <body> - mount to normal elements instead.`
)
return this
}
// 处理之后的template不可为空
if (process.env.NODE_ENV !== 'production' && !template) {
warn(
`Template element not found or is empty: ${options.template}`,
this
)
}
// template必须符合既定的几种规则,否则报错
if (process.env.NODE_ENV !== 'production') {
warn('invalid template option:' + template, this)
}
return this
处理template
// 如果没有render函数
if (!options.render) {
let template = options.template
// 有template模版
if (template) {
if (typeof template === 'string') { // 如果template是字符串按照字符串处理
if (template.charAt(0) === '#') {
template = idToTemplate(template)
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && !template) {
warn(
`Template element not found or is empty: ${options.template}`,
this
)
}
}
} else if (template.nodeType) { // 如果template是dom对象
template = template.innerHTML
} else {
if (process.env.NODE_ENV !== 'production') {
warn('invalid template option:' + template, this)
}
return this
}
} else if (el) { // 没有template但是有el
template = getOuterHTML(el)
}
if (template) {
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
mark('compile')
}
/// 按照处理完之后的template生成render函数
const { render, staticRenderFns } = compileToFunctions(template, {
outputSourceRange: process.env.NODE_ENV !== 'production',
shouldDecodeNewlines,
shouldDecodeNewlinesForHref,
delimiters: options.delimiters,
comments: options.comments
}, this)
options.render = render
options.staticRenderFns = staticRenderFns
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
mark('compile end')
measure(`vue ${this._name} compile`, 'compile', 'compile end')
}
}
}
上面的template主要对vue实例的options的template进行了判断处理,有render则按照传入的render函数处理,没有render则根据传入的option(template/el)生成相应的render函数。下面是几种template的四种写法,对应上面图中的四种:
第一种,没有template但是有el
<div id="app">
<div>
姓名: {{ name }}
</div>
</div>
const vm = new Vue({
el: '#app',
data: {
name: 'ludeng',
}
});
第二种,template以#开始
<template id="tmp">
<div>
姓名: {{ name }}
</div>
</template>
const vm = new Vue({
el: '#app',
template:'#tmp',
data: {
name: 'ludeng',
}
});
第三种,template是字符串且不以#开头
<div id="app"></div>
const vm = new Vue({
el: '#app',
template:`<div>姓名:{{ name }}<div>`,
data: {
name: 'ludeng',
}
});
第四种,template是一个dom对象
document.querySelector('#tmp')
<div id="app"></div>
<div id="tmp">
<div>
姓名: {{ name }}
</div>
</div>
const vm = new Vue({
el: '#app',
template:document.querySelector('#tmp'),
data: {
name: 'ludeng',
}
});
compileToFunctions生成render函数
import { compileToFunctions } from './compiler/index'
// 这个函数来源于platforms/web/compiler/index.js
// platforms/web/compiler/index.js
import { createCompiler } from 'compiler/index'
const { compile, compileToFunctions } = createCompiler(baseOptions)
// compiler/index 这里有parse,optimize,generate函数核心
import { createCompilerCreator } from './create-compiler'
export const createCompiler = createCompilerCreator(function baseCompile (参数){...})
// /create-compiler 这里有compile函数核心
在这里的createCompilerCreator 函数调用了createCompileToFunctionFn函数
return {
compile,
compileToFunctions: createCompileToFunctionFn(compile)
}
// createCompileToFunctionFn 函数在to-function文件中
export function createCompileToFunctionFn (compile: Function): Function {
return function compileToFunctions (){...}
}

所以实际上的核心代码还是在conmpiler/index文件中
compiler/to-function文件
入口文件entry-runtime-with-compiler执行的compileToFunctions的实现,其实就是该文件下的createCompileToFunctionFn 函数,函数内部主要执行了compile函数,compile函数来源于入参,而调用入参在 compiler/create-compiler文件中
export function createCompileToFunctionFn (compile: Function): Function {
const compiled = compile(template, options)
}
compiler/create-compiler文件
主要执行了baseCompile函数,该函数是函数来源于compiler/index文件中
export function createCompilerCreator (baseCompile: Function): Function {
return function createCompiler (baseOptions: CompilerOptions) {
function compile ( template, options ) {
...
const compiled = baseCompile(template.trim(), finalOptions)
...
}
return {
compile,
compileToFunctions: createCompileToFunctionFn(compile)
}
}
}
compiler/index文件
执行了compiler/create-compiler文件中的createCompilerCreator函数,入参如下
function baseCompile (
template: string,
options: CompilerOptions
): CompiledResult {
const ast = parse(template.trim(), options) // 重要
if (options.optimize !== false) {
optimize(ast, options) // 重要
}
const code = generate(ast, options) // 重要
return {
ast,
render: code.render,
staticRenderFns: code.staticRenderFns
}
总结
- 入口文件首先导入了Vue构造函数,该构造函数实际上在生成的时候做了一系列处理,但是这里先不解析
- 入口文件实现了$mount函数,该函数主要是对生成示例的options的template做一些检测(是否符合既定的template规则)和处理(生成相应的render函数)
- 生成render这个步骤,最核心的代码实际上是
compiler/index文件中的createCompilerCreator函数的参数函数,改函数生成了ast和render函数