解决迁移到vite项目中的router组件动态加载问题
解决迁移到vite项目中的router组件动态加载问题
问题描述
在迁移到vite项目后,使用component:()=>import(`/src/view/modules/${menu.component}\`.vue)
的方式引入的路由组件在本地环境正常使用,但在打包后的线上环境中报错,页面跳转白页,提示Failed to fetch dynamically imported module
。
问题分析
线上环境的问题可能是由于Vite的构建方式与本地环境不同,导致动态导入的模块在构建过程中被错误处理。
解决过程
- 原来使用require的方式引入,vite不支持这种引入方式,所以改成import方式引入,但是发现只修改成import不能正常运行,通过与线上老项目对比发现router中component在console.log中不相同,于是修改动态引入的代码。
- 修改成
component:()=>import()
后发现在本地使用时正常,发布到线上会报Failed to fetch dynamically imported module
,于是尝试修改component部分代码。 - 查阅Vite的文档,了解到Vite支持动态导入,但需要正确配置。
- 修改router组件的代码,尝试不同的导入方式。
- 尝试使用
const componentPath = `../views/modules/${menu.component}.vue`; component:modules[componentPath]
的方式
配置变更
- 修改router组件的代码,尝试使用
component:modules[componentPath]
的方式。
以下是package.json
和router.js
的部分代码:
package.json
{
"name": "your-project-name",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "vite",
"build": "vite build",
"serve": "vite preview"
},
"dependencies": {
"vue": "2.7.16",
"vue-router": "3.0.1"
},
"devDependencies": {
"@vitejs/plugin-vue2": "2.3.1",
"@vitejs/plugin-vue2-jsx": "1.1.1",
"vite": "^5.2.8",
"vue-template-compiler": "2.7.16"
}
}
router.js
//原代码
//import-production.js
// module.exports = file => () => import('@/views/' + file + '.vue')
// const _import = require("./import-" + process.env.NODE_ENV);
//修改后代码
let modules = import.meta.glob('../views/modules/**/**/*.vue')
console.log("🚀 ~ modules:", modules)
// ... (省略了部分代码)
// 添加动态(菜单)路由
function addDyRoute(menuList = [], routes = []) {
// 初始化一个空数组用于存储菜单列表
let menus = []
// 遍历菜单列表
menuList.forEach((menu, index) => {
// 如果菜单有子菜单,则将子菜单合并到menus数组中
if (menu.children && menu.children.length > 0) menus = [...menus, ...menu.children]
// 如果菜单没有子菜单,则处理当前菜单项
else {
// 为当前菜单生成唯一的menuKey
let key = utils.guid()
menu = Object.assign(menu, {
menuKey: key
});
let route = {};
// 克隆当前菜单项,为其添加meta信息
route = JSON.parse(JSON.stringify(menu))
let meta = {
menuKey: key,
// ... (省略了部分meta信息)
}
if (route.meta) Object.assign(route.meta, meta)
else Object.assign(route, meta)
// 如果菜单有组件并且不是布局组件且不是URL,则尝试动态引入组件
if (menu.component && menu.component.toLowerCase() !== 'layout' && !isURL(menu.path)) {
try {
//原代码
// route["component"] = _import(`@/views/modules/${menu.component}`.vue) || null;
const componentPath = `../views/modules/${menu.component}.vue`;
route = {
...route,
//本地好使,线上报错的版本
// component:()=>import(`@/views/modules/${menu.component}`.vue)
//修改后代码
component:modules[componentPath]
}
} catch (e) {
route["component"] = null;
}
} else if (isURL(menu.path)) {
// route["path"] = `i-${menu.menuKey}`;
// route["name"] = `i-${menu.menuKey}`;
// 将处理后的菜单项添加到routes数组中
route["meta"]["iframeUrl"] = menu.path;
}
routes.push(route)
}
})
// 如果menus数组中有子菜单,则递归调用addDyRoute函数
if (menus.length > 0) addDyRoute(menus, routes)
// 如果menus数组中没有子菜单,则处理最终的routes数组
else {
// ...
}
}
router.beforeEach(async (to, from, next) => {
NProgress.start();
// ...
api_menu.getMenus({
user_id: 1
}).then(res => {
console.log('路由列表', res);
if (res.data.code === 200) {
let menuList = res.data.data
// 动态加载路由
addDyRoute(menuList)
router.options.isAddDynamicMenuRoutes = true
sessionStorage.setItem('menuList', JSON.stringify(menuList || '[]'))
sessionStorage.setItem('permissions', '[]')
next({
...to,
replace: true
})
}
})
//...
})
结果
在修改代码和配置后,线上环境的问题得到解决,页面可以正常跳转。
经验教训
- 在迁移项目时,要注意新旧工具的差异,及时调整配置和代码。
- 对于动态导入,要确保正确配置和代码实现,以避免线上环境的问题。
- 在遇到问题时,要及时查阅官方文档和社区讨论,以便快速找到解决方案。
转载自:https://juejin.cn/post/7379792320156352552