[Vue源码分析] 模板的编译
最近小组有个关于vue源码分析的分享会,提前准备一下…
前言:
Vue有两个版本:Runtime + Compiler 、 Runtime only ,前者是包含编译代码的版本,后者不包含编译代码,编译过程需要借助webpack的vue-loader,接下来分析的是Runtime + Compiler版本,编译过程感觉挺复杂的,所以下边只是大概分析一下整个流程,源码理解直接写在源码中。
模板的编译
之前分析Virtual DOM的时候我们分析过模板到真实 DOM 渲染的过程,中间有一个环节把模板编译成render函数,这个过程称作编译。
(1)编译入口追踪
编译入口在分析virtual dom的时候已经提及过,位于src/platforms/web/entry-runtime-with-compiler.js
下的$mount
方法(红框部分):
可以看到compileToFunctions
方法将模板编译成了render
以及staticRenderFns
函数,通过对象的解构赋值获取结果并赋值给options
。
compileToFunctions在 src/platforms/web/compiler/index.js中定义,如下:
发现这是一个赋值的过程,值由createCompiler
产生,createCompiler
方法在 src/compiler/index.js 中定义,如下:
这个方法是createCompilerCreator
的返回值,createCompilerCreator
中传入的参数是一个方法,在此暂时不看参数方法里边的内容,因为这里只是一个调用,并没有执行什么。先看看createCompilerCreator
的定义,它的定义在src/compiler/create-compiler.js中,如下:
createCompilerCreator
返回一个 createCompiler
的函数,该函数返回的是一个对象,包括 compile
和compileToFunctions
, compileToFunctions
对应的就是$mount
方法中调用的compileToFunctions
方法,它是 createCompileToFunctionFn
方法的返回值,我们接下来看一下 createCompileToFunctionFn
方法,它的定义在 src/compiler/to-function/js 中,这个函数便是compileToFunctions
的最终定义,如下:
compileToFunctions
中编译的核心是compile
的调用,compile
是通过参数的方式传入的,也就是createCompilerCreator
中定义的compile
,现在我们返回去看compile
是什么,之前的图折叠了,现在展开如下:
compile
前部分代码都是在处理配置参数,实际上的编译过程只有代码中红框部分,也就是调用baseCompile
方法,这个方法时调用createCompilerCreator
时通过参数的方式传入的,也就是之前介绍到的当时说暂时不用看的代码,重新上一次图:
编译入口追踪到这里告一段落(vue项目支持多个平台,不同平台配置不一样,所以入口绕了很多个圈)。可以看到最终主要步骤有三步,一步是通过parse
生成ast
树,一步是optimize
,看英文意思及传入参数应该是对ast树进行优化的一个过程,一步是调用generate
生成code
,接下来看看这几个步骤都干了什么。
(2) parse
编译过程首先就是对模板做解析,生成 AST语法树,我们可以在parse后debugger一下,看看AST语法树的模样。
新建一个vue demo,在main.js做如下配置:
然后再源码中parse后打个断点,或者打印一下:
可以看到,控制台输入了以下内容,这便是ast的结构:
至此ast的结构我们了解了,但ast是怎么生成的呢?接下来我们看看parse是什么。parse的定义位于src/compiler/parser/index.js中。
这个过程很复杂,概括地说就是把template模板字符串转换成AST树,它是一种用JavaScript对象的形式来描述整个模板。整个parse的过程是利用正则表达式顺序解析模板,当解析到开始标签、闭合标签、文本的时候都会分别执行对应的回调函数,最终达到构造AST树的目的。
这块内容很多,挑几个点讲一下:
①:解析标签
解析HTML是通过调用parseHML方法完成的,它的定义位于src/compiler/parser/html-parser
调用:
定义:
这个方法也是比较复杂,整体来说就是循环解析template ,用顶部预先定义好的一堆正则表达式做正则匹配,处理开始标签和结束标签,对于不同情况分别进行不同的处理,直到解析完毕。
比较关键的一个点事在匹配的过程中会利用 advance 函数不断前进整个模板字符串,直到字符串末尾。
举个例子:
假如模板本来是这个样子的,可以理解为一个队列,目前队列的索引为0:
通过调用advance(4)后,通过html.substring(4),队列的索引就变成了4,当前待解析模板就变成了如下:
②:解析文本、表达式
除了处理开始标签和结束标签,还需要处理文本,通过parseText实现,源码位于src/compiler/parser/text-parsre.js
回头看看之前打印出来的ast,可以看到打上标记的表达式:
③:解析指令,以v-for为例
v-for指令解析的入口是processFor方法,该方法定义位于src/compiler/parser/index.js,此方法依赖parseFor以及extend方法,共同完成v-for的解析。
大概思路:通过正则匹配v-for,匹配到了就调用parseFor方法,parseFor方法位于同文件中:
这个方法也是通过正则匹配,分别匹配出不同的内容,比如’v-for="(item, index) in data"’,匹配出来的res.for是data,res.alias是item,res.iterator是index,随后返回解析出来的 结果,传给processFor中的res常量res,接着调用extend方法完成解析,extend方法的定义位于src/shared/util.js中,如下:
其实extend只是一个循环,把之前解析出来的属性循环出来并挂载到传入的ast对象上。(更新于2019.02.25 )
更多指令的解析有兴趣可以自行研究一下~~
[Vue源码分析] 模板的编译相关推荐
- [Vue源码分析] v-model实现原理
最近小组有个关于vue源码分析的分享会,提前准备一下- 前言: 我们都知道使用v-model可以实现数据的双向绑定,及实现数据的变化驱动dom的更新,dom的更新影响数据的变化.那么v-model是怎 ...
- vue源码分析系列二:$mount()和new Watcher()的执行过程
续vue源码分析系列一:new Vue的初始化过程 在initMixin()里面调用了$mount() if (vm.$options.el) {vm.$mount(vm.$options.el);/ ...
- [Vue源码分析]自定义事件原理及事件总线的实现
最近小组有个关于vue源码分析的分享会,提前准备一下- 前言: 我们都知道Vue中父组件可以通过 props 向下传数据给子组件:子组件可以通过向$emit触发一个事件,在父组件中执行回调函数,从而实 ...
- janusgraph源码分析1-下载编译启动 1
date: 2018-04-26 title: "janusgraph源码分析1-下载编译启动" author: "邓子明" tags: - 源码 - janu ...
- 【投屏】Scrcpy源码分析一(编译篇)
Scrcpy源码分析系列 [投屏]Scrcpy源码分析一(编译篇) [投屏]Scrcpy源码分析二(Client篇-连接阶段) [投屏]Scrcpy源码分析三(Client篇-投屏阶段) [投屏]Sc ...
- Vue源码分析——第三章
Vue源码分析--第一章 Vue源码分析--第二章 // only used in dev mode//检测 val必需是数字function checkDuration(val, name, vno ...
- v58.03 鸿蒙内核源码分析(环境脚本) | 编译鸿蒙原来很简单 | 百篇博客分析HarmonyOS源码
颜渊问仁.子曰:"克己复礼为仁.一日克己复礼,天下归仁焉.为仁由己,而由人乎哉?"颜渊曰:"请问其目."子曰:"非礼勿视,非礼勿听,非礼勿言,非礼勿动 ...
- Vue源码分析--Vue.component
Vue源码分析–Vue.component 我将非 Vue.component 的部分去掉了 export function initAssetRegisters (Vue: GlobalAPI) { ...
- vue源码分析系列三:render的执行过程和Virtual DOM的产生
render 手写 render 函数,仔细观察下面这段代码,试想一下这里的 createElement 参数是什么 . new Vue({el: '#application',render(crea ...
最新文章
- PHP artisan
- 将十六进制的字符串转换成整数
- 如何实现移动端轮播图的左滑右滑效果
- clover 主题_Clover主题更换
- 阿里P8架构师谈:Web前端、应用服务器、数据库SQL等性能优化总结
- Node.js进程管理之Process模块
- Log4j2架构分析与实战
- 【Flink】Flink反压(背压)网络流控
- fuel6.1搭建openstack
- H12-211数通HCNA题库解析(一)
- 编程c语言中文图形代码,C语言图形编程代码
- 100以内的奇数求和
- Go语言环境安装及配置
- html文字段落i排版,i排版怎么修改字体 字体排版详细介绍
- Ubuntu20.04上安装Gnuradio3.8并且实现Pluto的配置
- 二维码内置图片,并且把二维码放在图片指定位置上,画字,设置字本地样式,二维码批量生成
- graphpad饼状图_Graphpad绘制基因散点图
- 计算机组成原理 最新教材,《计算机组成原理(本科教材)》—甲虎网一站式图书批发平台...
- 风筝轮评测 风筝选购指南
- pytorch之迁移学习