Vue 2 动态组件异步导入失败问题求助
我通过<component v-bind:is="loaderComponent" />调用动态组件,代码如下:
export default { components: { 'loader': () => import(Vue.prototype.$VUE_LOADER_CONFIG.componentUrl) }, computed: { loaderComponent: function () { console.log('1', Vue.prototype.$VUE_LOADER_CONFIG.componentUrl) return 'loader' } } }
console.log能输出正确的组件路径,但组件就是加载不出来。只有把import里的变量换成硬编码的字符串路径(比如import('../../Loaders/SomeLoader'))才能正常工作。
报错信息如下:
[Vue warn]: Failed to resolve async component: function loader() {
return webpack_require("./src/base/components/Payment/Loader lazy recursive")(vue__WEBPACK_IMPORTED_MODULE_2__["default"].prototype.$VUE_LOADER_CONFIG.componentUrl);
}
Reason: Error: Cannot find module '../../Loaders/SomeLoader'
请问有什么解决思路?
这问题我之前也碰到过,本质是webpack对动态import的处理逻辑导致的,下面给你几个可行的解决方向:
1. 给webpack留好静态路径线索
webpack在打包阶段需要静态分析出要打包的模块,完全动态的import(变量)它没法识别。你得把路径拆成固定目录前缀和动态文件名的组合,让webpack能提前扫描到目标目录下的所有文件,比如:
// 把config里的完整路径改成只存组件文件名 'loader': () => import(`../../Loaders/${Vue.prototype.$VUE_LOADER_CONFIG.componentName}`)
这样webpack会把../../Loaders/下的所有文件都打包进懒加载chunk,运行时就能根据动态的文件名找到对应的模块了。
2. 提前注册所有可能的组件
如果你的loader组件数量不多,直接把所有loader都异步注册好,然后根据配置返回对应的组件名更稳妥:
export default { components: { SomeLoader: () => import('../../Loaders/SomeLoader'), AnotherLoader: () => import('../../Loaders/AnotherLoader') // 把所有用到的loader都列在这里 }, computed: { loaderComponent() { // 这里直接返回配置里的组件名,比如'SomeLoader' return Vue.prototype.$VUE_LOADER_CONFIG.componentName } } }
这种方式webpack能明确知道要打包哪些模块,不会有路径解析的问题,代码也更直观。
3. 检查路径细节
虽然console.log显示路径正确,但还是要确认几个点:
- 路径是相对于当前组件文件的吗?比如当前组件在
src/base/components/Payment/,../../Loaders/SomeLoader是不是真的指向正确的文件? - 文件扩展名有没有遗漏?有些项目配置了webpack可以省略
.vue扩展名,但如果没配置的话必须加上,比如import('../../Loaders/SomeLoader.vue')。
4. 用webpack的require.context批量导入
如果loader数量较多,还可以用webpack的require.context批量导入所有loader组件,然后根据配置匹配:
export default { computed: { loaderComponent() { // 创建上下文,扫描Loaders目录下的.vue文件 const loaderContext = require.context('../../Loaders/', false, /\.vue$/) // 根据配置的组件名找到对应的模块 const componentPath = `./${Vue.prototype.$VUE_LOADER_CONFIG.componentName}.vue` return loaderContext(componentPath).default } } }
这种方式不用一个个注册组件,webpack会自动扫描目标目录下的所有符合规则的文件,适合组件数量较多的场景。
内容的提问来源于stack exchange,提问作者Marek

