经常遇到打包编译一分钟的情况,这时候怎么办,到底是哪个插件慢,哪个插件报错。高级工程师经常要解决问题。本文会详细介绍如何 Debug 一个 vite 插件的思路。
当然你也可以使用这个成型的插件。开箱即用
回到正题,Vite 打包的流程是会先解析 Plugins,按插件排列依次顺序读取配置,然后依次执行插件中的不同钩子。
可以理解 Vite 或是 Webpack 都是一边一边运行相应的钩子函数
如何定位
根据上面的流程,我们可以通过穿插一个 Debug 插件来查看到底是哪卡住了。先用 LLM 写一个钩子函数
function createDebugPlugin(name) {
return {
name: `vite-plugin-debug-${name}`,
enforce: undefined, // 可以是 'pre', 'post' 或 undefined
// 配置解析完成后
configResolved(config) {
console.log(`[${name}] configResolved - 配置已解析`);
},
// 构建开始
buildStart(options) {
console.log(`[${name}] buildStart - 构建开始`);
},
// 解析 ID
resolveId(source, importer, options) {
// 只记录特定模块的解析
if (source.includes('vite') || source.includes('vue')) {
console.log(`[${name}] resolveId: ${source}`);
}
return null;
},
// 加载模块
load(id) {
// 只记录特定模
然后每个插件都插入一个,这样你就知道哪一个有问题。比如,
plugins: [
createDebugPlugin('after-mkcert'),
after-mkcert(),
createDebugPlugin('vue'),
vue()
]
汇总信息
这里有个知识点 enfore 属性,可以保证这个在最后一个执行。上 llm
// 创建一个专门用于跟踪插件完成情况的插件
function createFinalPlugin() {
return {
name: 'vite-plugin-final-tracker',
enforce: 'post', // 确保最后执行
configResolved(config) {
console.log(`[最终插件] 所有配置已解析`);
// 记录所有注册的插件名称
const pluginNames = config.plugins.map(p => p.name).join(', ');
console.log(`[最终插件] 已注册的插件: ${pluginNames}`);
},
buildStart() {
console.log(`[最终插件] 所有插件已初始化,构建开始`);
},
buildEnd(error) {
if (error) {
console.error(`[最终插件] 构建失败,错误信息:`, error);
} else {
console.log(`[最终插件] 所有插件已执行完毕,构建结束`);
}
},
closeBundle() {
console.log(`[最终插件] 整个构建过程已完成`);
}
};
}
错误嵌套
这是一个常用方法,如果你会好奇 apply 函数什么时候才能用到。这就是一个很好的场景
// 包装现有插件以添加错误处理
function wrapPluginWithErrorHandler(plugin, pluginName) {
const originalHooks = { ...plugin };
const wrappedPlugin = {
...plugin,
name: plugin.name || pluginName,
};
// 包装所有钩子添加错误处理
for (const hookName of Object.keys(plugin)) {
if (typeof plugin[hookName] === 'function' && hookName !== 'name') {
wrappedPlugin[hookName] = async function(...args) {
try {
return await originalHooks[hookName].apply(this, args);
} catch (error) {
console.error(`[错误] 插件 ${pluginName} 在 ${hookName} 钩子中出错:`, error);
throw error; // 继续抛出错误以便 Vite 处理
}
};
}
}
return wrappedPlugin;
}