现在我们来看 vm.$options.render 是在哪里定义的?
在 entry-runtime-with-compiler.js中我们可以看到
1 | const options = this.$options |
👇我们来看看compileToFunctions
1 | const { compile, compileToFunctions } = createCompiler(baseOptions) |
然后我们就来到了本文的重点compile 函数
compile 函数(src/compiler/index.js)就是将 template 编译成 render function 的字符串形式
1 | export const createCompiler = createCompilerCreator(function baseCompile ( |
createCompiler 函数主要通过3个步骤:parse、optimize、generate来生成一个包含ast、render、staticRenderFns的对象传给createCompilerCreator方法。
下面我们先看看parse:
1
2 > const ast = parse(template.trim(), options)
>
parse — 把HTML转换成AST树
AST 的全称是 Abstract Syntax Tree(抽象语法树),是源代码的抽象语法结构的树状表现形式,计算机学科中编译原理的概念。Vue 源码中借鉴 jQuery 作者 John Resig 的 HTML Parser 对模板进行解析,得到的就是 AST 代码。
Vue的AST节点
Vue自己是怎么来定义每个AST节点的呢?
1 | declare type ASTNode = ASTElement | ASTText | ASTExpression; |
Vue的AST节点有3类: ASTElement | ASTText | ASTExpression, 通过type来标记
parse函数
采用了 jQuery 作者 John Resig 的 HTML Parser ,将 template字符串解析成 AST。。
基本流程图

下面开始看parse函数的主要部分
1 | function parse(template) { |
parseHTML
我们可以发现关键是parseHTML,下面看下parseHTML
1 | export function parseHTML (html, options) { |
我们从标签开始的匹配开始看,这里我们先关注下parseStartTag和handleStartTag函数
假设我们传递这样一个html字符串
<div id="demo"></div>
parseStartTag函数
处理匹配到的开始标签部分(
),生成一个记录所有状态的对象match
1 | function parseStartTag () { |
返回的match应为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 > {
> tagName:'div',
> attrs:[[
> '',
> 'id',
> '=',
> 'demo',
> undefined,
> undefined
> start:6,
> end:14,
> groups: undefined,
> index:0,
> input: " id="demo">{{msg}}</div>"
> ]],
> start:0,
> end:28,
> unarySlash:''
> }
>
handleStartTag函数
下面看下handleStartTag函数,handleStartTag对match接着进行了改造
接着处理上一步返回的match对象, 对match改造成易用的对象, 去掉不需要的属性
1 | function handleStartTag (match) { |
进过再次处理后mack函数为
1
2
3
4
5
6
7
8 > {
> tagName ='' div'
> attrs = [{name: 'id', value: 'demo'}]
> unary=false
> match.start = 0
> match.end = 28
> }
>
到这里似乎一切明朗了许多,parseHTML主要用来蚕食html字符串,解析出字符串中的tagName, attrs, match等元素,传入start方法:
start方法
看下start(start 是从函数外部传入的函数),在compiler/parser/index.js中可见
1 | // start方法就是处理 element 元素的过程。确定命名空间;创建AST元素 element;执行预处理;定义root; |
通过createASTElement创建一个新的ASTElement对象, 并进行一系列操作
1 | export function createASTElement ( |
最终生成的AST语法树对象:
