目录
示例
源码
个人感觉应该是和vue2的实现总体一致的,故也按照这个思路来看
生成ast tree
将代码定位到compile函数,其接收入参为html标签的字符串形式(示例是直接使用的字符串,故不需要经过vue-loader的解析)和一些编译配置,即编译入口
接着又做了一些辅助函数的合并,用于编译时调用,如onError函数用于在出错时抛出错误信息
接着进入baseParse函数,查看具体的解析流程
createParserContext函数除了向options又添加了一些辅助api外,比较关键的一点是提供了template模板的标识位,比如初始时标识在第一行第一列,左侧无空格。
getCursor则相当于对上一步的返回对象进行了解构,获取到上图匡红的三个标识位
接着进入parseChildren,这应该是一个比较核心的函数了
从last函数可以推测出,vue每解析出一个元素就会将结果push进队列,由于对于嵌套元素而言,一定是先父元素的start标签再子元素的start标签,所以前一个必定是其父元素。当然,要保证这样一个前提,就必然需要在匹配到end标签的时候做对应的pop或shift操作。那接下来就具体来验证下猜想
进入while循环,正常来说都是正常的html元素标签
进入parseElement,通过注释可以看出,标签的解析分为开始标签、子元素、结束标签三部分进行处理
开始标签的处理
解析标签,校正标识位并将已经处理的字符从源字符中删除
解析标签属性,如class、id等,当前示例没有属性,故进行下修改
从代码可以看出,这主要包含三个步骤:
I-正则匹配id并保存至name
II-获取value的值
III-识别vue内置属性并处理
解析结果如下
子元素的处理
这会再次调用parseChildren对子元素作处理,对于子元素的开始标签而言,其处理逻辑和上边分析的一致。注意,此时的ancestors是有值的,值为上一个div的头标签,本次作为子元素的父元素(注意,当前非内置的html元素,在render和patch过程中将走mountComponent流程)
这显然会进行又是一次递归parseChildren的过程
最终得到的结果如下
代码回到id=appWrapper所在的parseElement中,将解析到的子元素信息通过children保留,以完成ast tree的创建
结束标签的处理
结束标签没有对属性的处理,因此只是单纯的在校正标识位,并做一些必要的错误校验
此时得到的完整的ast tree如下
ast tree补充
这一步我感觉是在对ast树做补充处理,它将一些只被vue识别的属性添加到了上边
生成代码字符串
生成代码字符串的过程其实和vue2差不多,也是在对ast tree进行解析,碰到不同的标识转换成不同的处理函数,最后通过new Function()的形式将其转换为可执行代码作为render函数在组件构建过程中被调用
当前生成的render函数如下
总结
模板编译就是对tenplate做分析,将符合vue语法规范的东西找出来