Vite是怎么识别.vue文件的? 或者说浏览器怎么识别到了.vue文件, 总体上来说, 点开浏览器中的.vue文件,可以看到内容已经不是真正的Vue SFC文件内容了, 而是经过编译的代码, 符合浏览器对JS的解析规范!
vite处理.vue文件大体如下步骤:
1. 读取到.vue文件
对于node来讲, 这个是可以的, 没有问题
2. 使用@vue/compiler-sfc解析读取到的文件内容
使用@vue/compiler-sfc的compileScript, compileTemplate, compileStyle三个方法分别解析vue文件的script, template, style模块, 解析到相应的代码字符串
3. 将解析到的代码字符串组装成Vue Component的范式
例如
const SomeComponent = {
name: 'SomeComponent,
data() {},
render() {}
}
4. 利用打包工具esbuild打包成浏览器能够识别的文件格式
完整代码如下:
main.vue
<template>
<div class="message">{{ message }}</div>
</template>
<script>
import { ref } from "vue";
export default {
name: "Main",
setup() {
const message = ref("Main");
return {
message,
};
},
};
</script>
<style scoped>
.message {
font-size: 60px;
font-weight: 900;
}
</style>
main.mjs
import pkg from 'fs-extra';
const { readFile, writeFile } = pkg;
import { parse, compileScript, compileTemplate, rewriteDefault } from "@vue/compiler-sfc";
import { build } from "esbuild";
import externalGlobalPluginPkg from 'esbuild-plugin-external-global';
const { externalGlobalPlugin } = externalGlobalPluginPkg;
async function main() {
const file = await readFile('./main.vue', 'utf8');
const { descriptor, error } = parse(file);
const id = Date.now().toString();
const scopeId = `data-v-${id}`;
const script = compileScript(descriptor, { id: scopeId });
const codeList = [];
codeList.push(rewriteDefault(script.content, "__sfc_main__"));
codeList.push(`__sfc_main__.__scopeId='${scopeId}'`);
const template = compileTemplate({
source: descriptor.template?.content,
filename: "main.vue", // 用于错误提示
id: scopeId,
});
codeList.push(template.code);
codeList.push(`__sfc_main__.render=render`);
codeList.push(`export default __sfc_main__`);
const code = codeList.join("\n");
await writeFile("build.temp.js", code);
await build({
entryPoints: ["build.temp.js"], // 入口文件
format: "esm", // 打包成 esm
outfile: "bundle.js", // 设置打包文件的名字
bundle: true, // bundle 为 true 才是打包模式
external: ["vue"],
plugins: [
externalGlobalPlugin({
vue: "window.Vue", // 将 import vue 模块,替换成 window.Vue
}),
],
});
}
main();