最近小组有个关于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 的函数,该函数返回的是一个对象,包括 compilecompileToFunctionscompileToFunctions对应的就是$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源码分析] 模板的编译相关推荐

  1. [Vue源码分析] v-model实现原理

    最近小组有个关于vue源码分析的分享会,提前准备一下- 前言: 我们都知道使用v-model可以实现数据的双向绑定,及实现数据的变化驱动dom的更新,dom的更新影响数据的变化.那么v-model是怎 ...

  2. vue源码分析系列二:$mount()和new Watcher()的执行过程

    续vue源码分析系列一:new Vue的初始化过程 在initMixin()里面调用了$mount() if (vm.$options.el) {vm.$mount(vm.$options.el);/ ...

  3. [Vue源码分析]自定义事件原理及事件总线的实现

    最近小组有个关于vue源码分析的分享会,提前准备一下- 前言: 我们都知道Vue中父组件可以通过 props 向下传数据给子组件:子组件可以通过向$emit触发一个事件,在父组件中执行回调函数,从而实 ...

  4. janusgraph源码分析1-下载编译启动 1

    date: 2018-04-26 title: "janusgraph源码分析1-下载编译启动" author: "邓子明" tags: - 源码 - janu ...

  5. 【投屏】Scrcpy源码分析一(编译篇)

    Scrcpy源码分析系列 [投屏]Scrcpy源码分析一(编译篇) [投屏]Scrcpy源码分析二(Client篇-连接阶段) [投屏]Scrcpy源码分析三(Client篇-投屏阶段) [投屏]Sc ...

  6. Vue源码分析——第三章

    Vue源码分析--第一章 Vue源码分析--第二章 // only used in dev mode//检测 val必需是数字function checkDuration(val, name, vno ...

  7. v58.03 鸿蒙内核源码分析(环境脚本) | 编译鸿蒙原来很简单 | 百篇博客分析HarmonyOS源码

    颜渊问仁.子曰:"克己复礼为仁.一日克己复礼,天下归仁焉.为仁由己,而由人乎哉?"颜渊曰:"请问其目."子曰:"非礼勿视,非礼勿听,非礼勿言,非礼勿动 ...

  8. Vue源码分析--Vue.component

    Vue源码分析–Vue.component 我将非 Vue.component 的部分去掉了 export function initAssetRegisters (Vue: GlobalAPI) { ...

  9. vue源码分析系列三:render的执行过程和Virtual DOM的产生

    render 手写 render 函数,仔细观察下面这段代码,试想一下这里的 createElement 参数是什么 . new Vue({el: '#application',render(crea ...

最新文章

  1. PHP artisan
  2. 将十六进制的字符串转换成整数
  3. 如何实现移动端轮播图的左滑右滑效果
  4. clover 主题_Clover主题更换
  5. 阿里P8架构师谈:Web前端、应用服务器、数据库SQL等性能优化总结
  6. Node.js进程管理之Process模块
  7. Log4j2架构分析与实战
  8. 【Flink】Flink反压(背压)网络流控
  9. fuel6.1搭建openstack
  10. H12-211数通HCNA题库解析(一)
  11. 编程c语言中文图形代码,C语言图形编程代码
  12. 100以内的奇数求和
  13. Go语言环境安装及配置
  14. html文字段落i排版,i排版怎么修改字体 字体排版详细介绍
  15. Ubuntu20.04上安装Gnuradio3.8并且实现Pluto的配置
  16. 二维码内置图片,并且把二维码放在图片指定位置上,画字,设置字本地样式,二维码批量生成
  17. graphpad饼状图_Graphpad绘制基因散点图
  18. 计算机组成原理 最新教材,《计算机组成原理(本科教材)》—甲虎网一站式图书批发平台...
  19. 风筝轮评测 风筝选购指南
  20. pytorch之迁移学习

热门文章

  1. Java 堆内存模型
  2. 小程序生成海报 详解
  3. React-Native学习笔记
  4. [整理+原创]ubuntu Thunderbird Mail设置自动提醒
  5. CentOS6.5下安装rzsz
  6. 基础才是重中之重~再说面向接口的编程
  7. Delphi使用Indy、ICS组件读取网页
  8. 深入 Lucene 索引机制
  9. #!(sha-bang)--脚本的开始
  10. HTML5学习笔记(三):HTML5的智能提示在VisualStudio2010