Vue3 defineAsyncComponent 动态导入的坑
Vue3defineAsyncComponent动态导入import.meta.globRollup
问题
使用 Vue3 的 defineAsyncComponent 通过变量路径动态导入组件,开发环境正常,生产构建后报错:
TypeError: Failed to fetch dynamically imported module:
http://localhost:4173/pages/drop-components/resume/Blank.vue
const AsyncComp = defineAsyncComponent({
loader: () => import(path),
loadingComponent: Loading,
});
原因
import(path) 中 path 是运行时变量,Rollup 在构建阶段无法静态分析这个动态路径。它不知道该打包哪些文件,也不知道打包后的 chunk 叫什么名字。
@rollup/plugin-dynamic-import-vars 可以缓解这个问题,但它对路径格式有严格要求,且功能有限。
方案一:遵循 dynamic-import-vars 格式约束
dynamic-import-vars 要求路径中最多只能有一段动态部分,且必须在当前目录或其子目录内:
import(`../components/${dir}/${name}.vue`);
这可以工作,但限制了目录结构,且路径越复杂越容易踩坑。
方案二:import.meta.glob(推荐)
Vite 提供的 import.meta.glob 在构建时展开所有匹配的文件,返回一个路径到模块的映射:
const modules = import.meta.glob('../components/**/*.vue');
const AsyncComp = modules[`../components/${dir}/${name}.vue`];
// AsyncComp 是一个返回 Promise<模块> 的函数,直接作为 defineAsyncComponent 的 loader
构建时 Vite 会将 glob 模式展开为静态的模块映射表,不再依赖运行时路径解析。AsyncComp() 直接作为 defineAsyncComponent 的 loader 使用。
小结
动态导入的坑本质上是一个构建时与运行时的信息不对称问题。import.meta.glob 用编译期展开绕开了这个限制,是 Vite 项目中最干净的方案。