跳到主要内容

插件原理窥探

/**
* @type import("vite").UserConfig
*/
// 插件其实就在vite的不同阶段调用不同的钩子
const viteTestConfig = {
plugins: [
{
config(options) { },
configureServer(server) { },
transformIndexHtml(html) { },
configResolved(options) { },
configurePreviewServer(server) { },
/* 上面是vite独有的钩子,下面是通用钩子,会各自执行一次 */
// 以下钩子在服务器启动时被调用
options(rollupOptions) { },
buildStart(rollupOptions) { },
// 以下钩子会在每个传入模块请求时被调用
resolveId(rollupOptions) { },
load(rollupOptions) { },
transform(rollupOptions) { },
// 以下钩子在服务器关闭时被调用
buildEnd(rollupOptions) { },
closeBundle(rollupOptions) { }
}
]
}
export default viteTestConfig

我们在vite-dev-server中引入了vite的配置

const viteConfig = require("./vite.config");

我们读到配置文件以后执行生命周期的一些函数,伪代码如下

viteConfig.plugins.forEach(plugin=>plugin.config && plugin.config(viteConfig,...))

const mergeOptions = Object.assign({},defaultConfig,viteConfig,terminalConf)

viteConfig.plugins.forEach(plugin=>plugin.configResolved && plugin.configResolved(mergeOptions,...))

那么什么时候用transformIndexHtml呢,我们发现请求html文件时,读取到文件以后不急着给用户,原本逻辑如下

if (ctx.request.url === "/") {
const indexContent = await fs.promises.readFile(path.resolve(__dirname, "./index.html")); // 在服务端一般不会这么用
ctx.response.body = indexContent;
ctx.response.set("Content-Type", "text/html");
}

在返回前执行插件进行转换

if (ctx.request.url === "/") {
const indexContent = await fs.promises.readFile(path.resolve(__dirname, "./index.html")); // 在服务端一般不会这么用
let cacheIndexHtml = indexContent
viteConfig.plugins.forEach(plugin=>{
if(plugin.transformIndexHtml){
cacheIndexHtml = plugin.transformIndexHtml(cacheIndexHtml)
}
})
ctx.response.body = cacheIndexHtml;
ctx.response.set("Content-Type", "text/html");
}