欢迎光临散文网 会员登陆 & 注册

vue源码分析学习--编译阶段汇总

2023-01-23 11:52 作者:坏蛋Dan丶  | 我要投稿

前言

我们从vue-loader开始,一步一步分析到vue/compiler-core包源码,那么这编译阶段我们就分析完了(这里忽略compiler-ssr) 。

这里涉及到了几个包,我们来整理一下。

文章在知乎上,阿B的文章编辑器是真的那啥。。。。。

https://zhuanlan.zhihu.com/p/600569554


入口

https://zhuanlan.zhihu.com/p/572808664

我这里分析的是基于webpack的,所以入口是vue-loader

简单的说下这里面做了什么。

首先在调用vue-loader之前需要先安装vueLoaderPlugin

vueLoaderPlugin

这里面主要做了几件事

  1. vue-loader标志位置为true,这样webpack编译器就可以调用vue-loader了。

  2. 复制一份包含所有loaderrules(不包含vue-loader),分别给它们加上resouceresourceQuery,这俩是用来确认请求的vue资源是否可以被该loader处理的,这里不用担心会影响到其它的loader

  3. copyrules中注入templateLoader,这样在资源是vuetemplate的时候就会被识别到并且最终处理成render function。注意render functionjs代码,所以它也需要被其它loader识别处理。

  4. 插入css-post-loader用来处理vuestyle,这里需要注意顺序,得在style loadercss loader之前执行。

  5. 改写request资源的路径,这样才能被vue-loader识别到。

  6. 覆盖原来webpack compilerrules

然后回到vue-loader中,根据请求路径返回对应的资源。这里说下script部分没有loader,所以在vue-loader识别到请求的参数是js的才会调用@vue/compiler-sfccompileScript来处理并返回内容。

不同的loader调用不同的@vue/compiler-sfc方法处理不同的部分:

  • compileTemplate:被templateLoader调用,用来处理template部分;

  • compileScript:被vue-loader自身调用,用来处理script部分;

  • compileStyle:被css-post-style调用,用来处理style部分;

处理完后的资源在vue-loaderruntime拼接之后再传递给下一个loader

compiler-sfc

那么入口分析完了,就轮到被调用的包了。

https://zhuanlan.zhihu.com/p/591218245

compileScript

https://zhuanlan.zhihu.com/p/589386136

上面说了处理script部分是通过compileScript这个方法来处理的,在这个文件中核心是调用babel来处理js代码转换为AST节点,然后基于AST 节点做处理。

场景很多,这里简单的说下:

  1. 没有setup语法糖blockscript,按optionApi的方式来处理

  2. setup语法糖blockscript且有non setup blockscript,都处理,其中non setup block处理之后整合到setup block的顶部。而setup block处理成非语法糖的写法。

注意:所有的语法糖都只是方便使用,而在编译阶段的都会转化成原本的写法。

compileTemplate

https://zhuanlan.zhihu.com/p/590240402

这里没怎么处理,调用的是在compiler-dom包里,但是核心处理是在compiler-core里。

compileStyle

https://zhuanlan.zhihu.com/p/591215117

核心是调用postcss[1] 来处理。

然后如果有lang的话,调用对应的预处理器先。比如lang="scss",那么再开始调用postcss解析之前会先调用sass-loader来处理一遍。

其他没什么好说的了,但是有个点这里要提一下,就是处理cssVar

vue在调用之前自定义了一个postcss 插件cssVarsPlugin,这个插件就是用来处理vue3.xcss变量的方式。比如color: v-bind(color)会变成var(--color)的方式。

vue3.x中使用css变量: SFC CSS Features | Vue.js (vuejs.org)

另外还有一个点,就是scopeId

每一个sfc文件都会有一个对应的scope Id,如果这个style block有要求scoped,那么就会给每个css rule加上scopeId

compiler-dom

https://zhuanlan.zhihu.com/p/594633057

你应该注意到了,上面compiler-sfc处理完了之后其实只剩下了template没有处理好了,而script、style都已经是可以运行在浏览器中的最终代码了。

而接下来compiler-dom以及compiler-core其实都是在处理template相关的,因为template只是一段长得像htmljs代码。

不过尴尬的是html解析引擎不认识它,js的引擎也不认识它。

所以这里就需要自行去把这template处理成js代码。

compiler-dom这个包是compiler-core的上游包,也就是基于compiler-core封装的,加上了一些插件。

这个包没啥好说的,感兴趣的可以去看下。

不过这里有几个点需要注意:

  1. v-on/v-model等的modifiers也就是修饰符的处理是放到这个包里的

  2. 过滤style\script标签也是放在这个包里,这俩标签不应该再出现了(svg标签里的style和这里的不同)

  3. 是否可以staticStringify的判断和处理都是在这个包中。

compiler-core

https://zhuanlan.zhihu.com/p/600566832

这个包是处理template的核心部分

我直接把之前画的图贴出来,应该已经很清晰了。

img_core_pacakge_work_flow

可以参考babelcore包的架构。

简单地说就是把template这一段字符串通过parse变成AST,然后通过transform遍历所有节点通过不同插件处理节点,接着通过generate生成render function。这个时候的render function已经是浏览器可以执行的runtime js代码了。

优化

这里面关于优化的东西我都没有分析,这里就简单说下我遇到过的优化:

  1. cache,这个cacheruntime的,比如指令的value是一个表达式,那么表达式的结果其实是可以缓存的,这样每次调用返回缓存即可。而compile阶段的缓存更多的是和hot-reload搭配的,在下一次编译的时候可以过滤掉。

  2. staticHoist,这个我们是有分析的,因为在主流程中。通过判断不同的点,比如属性是否是静态之类的来判断这个节点是否每次都需要create,如果不需要就把它提升到顶部,这样就只需要create一次。注意这个是runtime的优化。另外这里可以hoist不只有dom节点,还有属性节点等也是可以的。

  3. staticStringify,这个是在staticHoist的基础上,如果不满足hoist的条件那就一定不满足stringify的条件。stringify使用的是innerHTML的方式插入,所以只有这一块代码中节点数量/指令数量达到了一定的个数时才会stringify,因为如果数量少,其实innerHTML插入的性能没啥提升。

  4. PatchFlag,也就是插旗,给不同类型的节点插旗,这样可以快速定位需要如何处理,在patch的时候diff就能绕过一些逻辑,减少diff的时间和损耗。

  5. track,实际上和插旗一样,跟踪上面的flag,如果没有flag的节点,那diff阶段就可以skip了。


总结

那么编译阶段的源码我们就都分析完了,这一套分析下来其实我个人学到的东西非常非常多,整个vue的编译流程也比以前清晰的多。


现在也不再觉得这是魔法了~


最后如果觉得对你有帮助的话请务必点个赞~


最后的最后,祝大家新春快乐!!


vue源码分析学习--编译阶段汇总的评论 (共 条)

分享到微博请遵守国家法律