首先在vite.config.ts文件中里的'@vitejs/plugin-vue'插件引入的vue()方法根据断点内部会执行 vuePlugin方法,
function vuePlugin(){
let options = {
isProduction: process.env.NODE_ENV === "production",
compiler: null,
...rawOptions,
include,
exclude,
customElement,
reactivityTransform,
root: process.cwd(),
sourceMap: true,
cssDevSourcemap: false,
devToolsEnabled: process.env.NODE_ENV !== "production"
};
return {
name: "vite:vue",
handleHotUpdate(ctx) {.....},
configResolved(config) {....},
configureServer(server){...},
buildStart(){....}
async resolveId(){...}
load(id, opt) {.....},
transform(code, id, opt) {....}
}
其中在pnpm dev之后执行的为buildStart
buildStart() {
options.compiler = options.compiler || resolveCompiler(options.root);
},
buildStart为options.compiler赋值,如果无回调用 resolveCompiler方法
function resolveCompiler(root) {
const compiler = tryRequire("vue/compiler-sfc", root) || tryRequire("vue/compiler-sfc");
if (!compiler) {
throw new Error(
`Failed to resolve vue/compiler-sfc.
@vitejs/plugin-vue requires vue (>=3.2.25) to be present in the dependency tree.`
);
}
return compiler;
}
const _require = node_module.createRequire((typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.src || new URL('index.cjs', document.baseURI).href)));
function tryRequire(id, from) {
try {
return from ? _require(_require.resolve(id, { paths: [from] })) : _require(id);
} catch (e) {
}
}
根据resolveCompiler 基本上确认compiler赋值为获取vue/compiler-sfc模块的东西此时一阶段完成
后续在打开网页时会调用transform方法,期间会调用其他文件目录下获取数据编译。在遇到app.vue后会调用transformMain方法,之后调用createDescriptor创建了descriptor对象生成了ast语法树,descriptor对象内部已经有styles数组,templat与scriptSetup构成vue的3个部分。
async function transformMain(code, filename, options, pluginContext, ssr, asCustomElement) {
const { devServer, isProduction, devToolsEnabled } = options;
const { descriptor, errors } = createDescriptor(filename, code, options);
//判断errors后后看是否报错,就不写了。
const { code: scriptCode, map: scriptMap } = await genScriptCode(
descriptor,
options,
pluginContext,
ssr
);
if (hasTemplateImport) {
({ code: templateCode, map: templateMap } = await genTemplateCode(
descriptor,
options,
pluginContext,
ssr
));
}
const stylesCode = await genStyleCode(
descriptor,
pluginContext,
asCustomElement,
attachedProps
);
}
之后就是genScriptCode genTemplateCode genStyleCode 三大块各自编译解析。
genScriptCode部分
async function genScriptCode(descriptor, options, pluginContext, ssr) {
let scriptCode = `const _sfc_main = {}`;
let map;
const script = resolveScript(descriptor, options, ssr);
}
resolveScript函数讲vue的部分编译为乐js文件
之前
<script setup lang="ts">
// This starter template is using Vue 3 <script setup> SFCs
// Check out https://vuejs.org/api/sfc-script-setup.html#script-setup
import HelloWorld from './components/HelloWorld.vue'
</script>
<template>
之后
import { defineComponent as _defineComponent } from 'vue'
import HelloWorld from './components/HelloWorld.vue'
export default _defineComponent({
__name: 'App',
setup(__props, { expose: __expose })
{ __expose();
// This starter template is using Vue 3 <script setup> SFCs
// Check out [https://vuejs.org/api/sfc-script-setup.html#script-setup
const __returned__ = { HelloWorld }
Object.defineProperty(__returned__, '__isScriptSetup', { enumerable: false, value: true })
return __returned__
}
})
在resolveScript内部调用了vue/compiler-sfc的compileScript方法
genTemplateCode部分
调用了transformTemplateInMain 核心方法 compile
function transformTemplateInMain(code, descriptor, options, pluginContext, ssr) {
const result = compile(code, descriptor, options, pluginContext, ssr);
return {
...result,
code: result.code.replace(
/\nexport (function|const) (render|ssrRender)/,
"\n$1 _sfc_$2"
)
};
}
//compile 部分
function compile(code, descriptor, options, pluginContext, ssr) {
const filename = descriptor.filename;
const result = options.compiler.compileTemplate({
...resolveTemplateCompilerOptions(descriptor, options, ssr),
source: code
});
return result;
}
在调用compileTemplate后走到doCompileTemplate该两个都是@vue/compiler-sfc文件下的方法。
总结
- vuePlugin
- buildStart //获取挂载vue/compiler-sfc
- transform //编译三大部分
-
- transformMain - createDescriptor //获取Descriptor - genScriptCode // - genStyleCod - genTemplateCode
- buildStart //获取挂载vue/compiler-sfc