坏蛋Dan
知乎@坏蛋Dan
发布时间:2024.1.4

前言

昨天我们分析了setup如何处理props等,今天我们接着往下分析。

坏蛋Dan:vue/compiler-sfc源码分析学习--part2:如何处理script--day4

感兴趣的大佬可以看下


正文

今天是分析如何处理script的最后一天了,加油!

生成setup的返回语句

  • allBindings: 俩script block数据的集合。
  • hasDefaultExportRender: 是否有render函数,比如这种{ render: (h) => {} }
  • compileTemplate: 来自./compileTemplate.ts,看名字就知道是用来处理template模板的。
  • generateCodeFrame: 生成错误提示语的,比如下划线标记之类的,这个就不看代码了,无关紧要。
  • unref[1]:前面应该漏了这玩意儿,它其实是一种语法糖,是val = isRef(val) ? val.value : val的简写。

这一大段其实做的事情很简单,就是判断你是使用template还是inlineTemplate还是使用的render函数。

由于我们用的是常规的template,所以这里只会走第一部分的逻辑。

可以看到returned实际上就是我们的变量、函数、类、导入的方法等。不过有一点需要注意,那就是definePropsdefineEmits以及defineExpose的都不在这里面。至于他们会在哪,后面会说到。

至于inline或者render函数方式,我们有空再分析。


组转export default

  • hasDefaultExportName: 之前分析non script block的时候有说到过,这里就是判断你export的对象中是否有name字段。为啥这里一定要有个name呢?因为方便vue-tool在浏览器生成节点时命名节点。
  • hasInlinedSsrRenderFn: 和ssr相关的,是否有ssrrender函数,我们不会分析ssr相关的,所以这里忽略。
  • propsRuntimeDecl: 老朋友了,当然如果忘了这里再说下,就是你传入defineProps中的对象。
  • propsDestructureDecl: 也是老朋友了,props解构赋值的那个节点。
  • propsDestructuredBindings:节点转换成的数据

  • genDestructuredDefaultValue: 看名字就知道是用来获取解构赋值中的默认值的。
  • helper: 前面也说过了,将runtime辅助函数存储到helperImport中。
  • propsTypeDecl: defineProps使用only-type场景的类型定义。
  • genRuntimeProps: 代码就不看了,简单的说下做了什么,里面会根据你的类型定义转化成runtimeprops,毕竟浏览器不认识ts。另外还有个点我把代码贴出来

除了是boolean类型或者带有默认值的函数类型需要保留之外,其余的都会移除类型定义。

  • emitsRuntimeDecl: 同props
  • emitsTypeDecl: 同上。
  • hasDefineExposeCall: 前面好像没说过?这个是判断是否用了defineExpose的,会被转换成export default对象中的expose()方法。
  • defaultExport: 默认导出的,比如export { xx as default } from 'xx.js'
  • hasAwait: 是否有直接在setup block中使用await的,这个也是之前文章中提到好几次的,这里就不说如何处理这个场景的了,总之是允许你在setup语法糖下直接await而不需要async的。

这一大段看完代码估计大家都知道是在干啥了吧?

将之前的数据组装成非setup语法糖的样子,不多说,直接看数据。另外有个点就是之前的__default__,这里面包括non setup blockexport以及别的包导入的比如export { x as default } from 'xx',最终都会合并到一起再export default导出。

而最终转换的script代码由于太长,这里就直接以代码的形式贴出来。

这回一目了然了,感觉前面说的一堆解析还不如这里直接贴出来最终代码。

这里有几处地方你们应该注意到了

  1. import的语句包括non setup script block中的import都会被移动到头部,也就是顶级作用域。
  2. export { x as default } from 'xx'或者non setup block中的export default都会被合并到__default__中,然后和我们的setup block中的export default合并组合成最终的export default
  3. setup函数中return出去的东西是包括non setup block
  4. defineExpose会被转换为expose方法
  5. defineProps、defineEmits等方法的import都被移除了,实际上并不需要开发者去导入。
  6. props、emits的定义都会被移到setup外部,这也就解释了为什么你在defineProps、defineEmits中引用local变量(setup函数中的变量)会报错了。
  7. props、emits、expose赋值给的变量都会被处理迁移到setup函数的参数中,上面埋下的坑这里补上了。
  8. setup block中直接使用await的会被处理成一个立即执行函数,具体怎么做之前的文章里有说。
  9. 如果用了await,这里setup函数会给你加上async
  10. css变量会被处理成一个带有scopedId的字段,然后在组件创建时执行,具体怎么做的,之前的文章里也有说到过了,这里就不多说了。
  11. $ref语法糖被处理成ref,连同xxx = aa被处理成xxx.value = aa

加入辅助函数到源码中

这个就不多说了,我们直接看下数据

这些都是runtime需要的辅助函数

这里面就mergeDefaults没说过,不过这个简单说就是合并默认值的操作。


返回最终数据

没啥好说的。。。


总结

今天是分析如何处理script的最后一天,我们终于看到了最终的代码长啥样了。

简单的说主要就是在将setup语法糖处理成非语法糖的样子,这里面最麻烦的就是props的处理了。。

参考

  1. ^vue3.x-unref https://vuejs.org/api/reactivity-utilities.html#unref

发布于 2022-12-05 16:59・IP 属地广东