Vue3源码:SFC、AST

144 阅读2分钟

转换效果

转换前:

<script setup>
import {ref} from "vue";
let aaa = ref(100);
let bbb = ref(200);
let color = ref('aquamarine');
const vFocus = {
  mounted: (el) => el.focus()
}
function changeNumber() {
  aaa.value++
}
</script>

<template>
  <div>
    <div @click="changeNumber" :style="{color: color}">father</div>
    <input v-focus>
    <div class="list">{{ aaa }} + {{ bbb }}</div>
  </div>
</template>

<style scoped>
.list {
  height: 40px;
  border: 1px solid blue;
  background-color: aquamarine;
}
</style>

转换后:

 import { createHotContext as __vite__createHotContext } from "/@vite/client";import.meta.hot = __vite__createHotContext("/src/App.vue");import {ref} from "/node_modules/.vite/deps/vue.js?v=f9dcc282";
 
 const _sfc_main = {
    __name: 'App',
   setup(__props, { expose: __expose }) {
    __expose();
  
  let aaa = ref(100);
  let bbb = ref(200);
  let color = ref('aquamarine');
  const vFocus = {
    mounted: (el) => el.focus()
}
function changeNumber() {
    aaa.value++
}
 
const __returned__ = { get aaa() { return …mport.meta.hot.accept(mod => {
    if (!mod) return
    const { default: updated, _rerender_only } = mod
   if (_rerender_only) {
      __VUE_HMR_RUNTIME__.rerender(updated.__hmrId, updated.render)
  } else {
      __VUE_HMR_RUNTIME__.reload(updated.__hmrId, updated)
  }
})
import _export_sfc from "/@id/__x00__plugin-vue:export-helper"
export default /*#__PURE__*/_export_sfc(_sfc_main, [['render',_sfc_render],['__scopeId',"data-v-7a7a37b1"],['__file',"D:/testone/vite4/vite-vue/vue3-base/src/App.vue"]])

转换过程:

一、.vue文件转换成ast

转换后的结构

image.png
code:.vue文件通过fsp.readFile(file, "utf-8")获取到的字符串,在loadAndTransform这步就获取,parse以code为准解析生成对象结构,即ast
parse:

`parse``baseParse``createRoot`:创建root对象
        `parse`:通过this.state状态循环解析code字符串
            `stateText`:(state == 1)
            `stateBeforeTagName`:(state == 5)
            `stateInSFCRootTagName`:(state == 34)
                `handleTagName`:通过isEndOfTagSection判断是tag末尾
                    `onopentagname`:获取标签名(如:script、template等)及相关信息
                    `stateBeforeAttrName`:
            `stateBeforeAttrName`:(state == 11)
                `handleAttrStart`:记录属性起点位置
                    `ondirname`:遇到 @ : . # 自定义指令 时进入,创建相关属性
            `stateInAttrName`:(state == 12)
                `onattribname`:获取标签内属性(如:setup)
                `handleAttrNameEnd`:
                `stateAfterAttrName`:
                    `stateBeforeAttrName`:
                        `endOpenTag`:
                            `isVoidTag`:
            `stateInRCDATA`:(state == 32)
                `fastForwardTo`:快速循环到script结束标签,中间回车位置记录在newlines数组中
            `stateInTagName`:(state == 6)
                `handleTagName`:获取标签名(如:div)
            `stateInDirArg`:(state == 14)
                `ondirarg`:在属性对象里创建arg,(如:在解析完@click)
            `stateBeforeAttrValue`:(state == 18) 
            `stateInAttrValueDoubleQuotes`:(state == 19)
                `onattribdata`:获取属性绑定字段(如:@click绑定的changeNumber字符串)
                `onattribend`:获取属性绑定字段相关属性
            `stateInClosingTagName`:(state == 9) 生成标签对象结构(ast)
                `onclosetag`:之前在stack栈中存的标签(如:div),现在标签结束将其取出
            `stateInDirName`:(state == 13)(自定义指令结束会进入)
                `ondirname`:遇到 @ : . # 自定义指令 时进入,创建相关属性
            `stateInterpolationClose`:(state == 13)模板语法({{}})结束会进入
                `oninterpolation`:生成模板内容(如:aaa)属性对象
        `condenseWhitespace`:清除root.children中只有回车的部分,现在只剩script、template、style

二、遍历ast.children生成新文档

`transformMain`:
    `createDescriptor`:
        const { descriptor, errors } = compiler.parse  转ast过程
        descriptor.id = getHash 生成hash值
    `genScriptCode`:拼接根据script生成的内容
        `resolveScript`:
            `compileScript`:
                `parse`:根据script内容生成scriptSetupAst或scriptAst
    `genTemplateCode`:拼接template内容
        `transformTemplateInMain`:
            `compile`:
                `compileTemplate`:
                    `doCompileTemplate`:
                            `compile`:
    `genStyleCode`:拼接引入css的路径
    ......:继续拼接其他字段

相关数据结构:

scriptSetupAst:这里6个对象对应SFC文件script标签中的6条语句\

image.png