踩坑记15 动态路由 router.options.routes未更新 | vue升级 element-plus未适配vue3.2.x | vite glob导入动态加载组件,不能使用别名alias

牟波
2023-12-01

2021.8.12

坑50(vue-router4、addRoute()、router.options.routes未更新):进行动态权限获取菜单的设置,使用了addRoute()来添加路由,但是router.options.routes未更新,依然只有原来的路由列表值。

相关API简要介绍:

addRoute(),添加一条新的路由记录到路由,文档: API 参考 | Vue Router (vuejs.org)

router.options.routes,应该添加到路由的初始路由列表,文档: API 参考 | Vue Router (vuejs.org)

解决方案:

方法一(router.options.routes.push()):在拿到菜单数据并生成相应路由列表后,在用router.addRoute()添加路由记录的同时,向router.options.routes中push()对应路由。

menuRoutes.map((r)=>{

    router.addRoute(r)

    router.options.routes.push(r)

})

方法二(vuex中的routes生成菜单):使用vuex,在store中存储路由列表,并用其生成菜单,避开router.options.routes。(认为可行,但并未实现)

参考文章: 在addroutes后,$router.options.routes没有更新的问题(手摸手,带你用vue撸后台 读后感) - 湛蓝玫瑰 - 博客园 (cnblogs.com)手摸手,带你用vue撸后台 系列二(登录权限篇) - SegmentFault 思否

参考源码: 

vue-element-admin 基于vue2 GitHub - PanJiaChen/vue-element-admin: A magical vue admin https://panjiachen.github.io/vue-element-admin

web-flash 在vue-element-admin基础上二次开发 GitHub - enilu/web-flash: web-flash -- Admin Framework and Mobile Website Based on Spring Boot and Vue.js

注意!参考源码使用的是vue2,对应的vue-router3,使用的 router.match API已被删除,改为 router.resolve。详见文档: API 参考 | Vue Router (vuejs.org)。router.match 和 router.resolve 已合并到 router.resolve 中,签名略有不同。

坑51(vite2、vue3、element-plus、error):问题产生在更新了以下三个包后:@vitejs/plugin-vue,1.3.0到1.4.0;@vue/compiler-sfc,3.1.5到3.2.2;element-plus,1.0.2-beta.69到1.0.2-beta.70。当前vue3版本3.1.5。

运行出现error如下:

Uncaught SyntaxError: The requested module '/node_modules/.vite/vue.js?v=50ccac76' does not provide an export named 'createElementBlock'

快速解决:原因是@vue/compiler-sfc版本升级到3.2.x最新版本后,与3.1.5版本的vue不匹配,npm install @vue/compiler-sfc@3.1.5,使vue和@vue/compiler-sfc都为3.1.5版本即可消除error。如果想更新到最新版vue3,npm install vue@next。但是如果使用了element-plus当前最新版本1.0.2-beta.70依然依赖vue@3.1.x版本,更新会报错,暂不建议更新。2021.8.12

具体排查(踩坑坑坑坑坑):

首先看了一下@vitejs/plugin-vue的1.4.0版本的更新信息,可以看到:

* Custom Elements mode behavior changed: now only inlines the CSS and no longer exports the custom element constructor (exports the component as in normal mode). Users now need to explicitly call defineCustomElement on the component. This allows the custom element to be defined using an async version of the source component.

简单理解:自定义元素模式行为改变,现在只内联CSS,并且不再导出自定义元素构造函数(像在正常模式下一样导出组件)。用户现在需要在组件上显式调用的 defineCustomElement 。这允许使用源组件的异步版本定义自定义元素。

ps:关于defineCustomElement可参考 Vue 3.2发布啦,站起来继续学!-Vue.js-PHP中文网 和 尤雨溪凌晨官宣:Vue 3.2 已发布 - 知乎 (zhihu.com)

在代码中搜索createElementBlock、defineCustomElement、_createElementBlock,均无结果。

于是尝试直接退回@vitejs/plugin-vue版本到1.3.0,npm install @vitejs/plugin-vue@1.3.0。依然报错。

搜索相关资料,发现此篇:[Bug Report] Uncaught SyntaxError: The requested module '/node_modules/.vite/vue.js?v=a348567b' does not provide an export named 'createElementBlock' · Issue #2907 · element-plus/element-plus · GitHub,于是将element-plus的版本也退回到1.0.2-beta.69。依然报错。

于是退回今天最后一项更新的包:@vue/compiler-sfc到3.2.1,报错,退回到3.1.5(3.2.0前最后一个版本),无错误了。

之后npm install element-plus@1.0.2-beta.70,无错误;npm install @vitejs/plugin-vue@1.4.0,无错误。

看来就是@vue/compiler-sfc版本在3.2以上的原因。

检查了一下,现在vue和@vue/compiler-sfc版本都是3.1.5,无错误。

因为vue3用的是next版本,所以ncu查找不到更新,只找到了@vue/compiler-sfc的更新信息。

接下来,查看vue的npm包,npm info vue,查到vue@2.6.14;npm info vue@next,查到vue@3.2.2;下方详情中都有dist-tags可以看到当前各版本情况:beta: 3.2.0-beta.8  csp: 1.0.28-csp     latest: 2.6.14      next: 3.2.2。

于是,修改package.json,将vue和@vue/compiler-sfc的版本都从3.1.5改为3.2.2,npm install,报错:

npm ERR! Could not resolve dependency:

npm ERR! peer vue@"3.1.x" from element-plus@1.0.2-beta.70

备份后删掉package-lock.json和yarn.lock,再次尝试npm install,一样报错。

嗯,那就等element-plus团队适配vue3.2.x以后再更新了。

备份的package-lock.json和yarn.lock放回去,package.json里vue和@vue/compiler-sfc的版本改回3.1.5,npm install确定一下没问题。

坑52(vite2、vue3、glob、动态加载组件):在动态加载路由时,使用如下代码,import动态加载组件(child.component的值为组件地址),会报错,见下方。

component:()=>import(`@/${child.component}`)

启动后,vite报warning:

The above dynamic import cannot be analyzed by vite.

See https://github.com/rollup/plugins/tree/master/packages/dynamic-import-vars#limitations for supported dynamic import formats. If this is intended to be left as-is, you can use the /* @vite-ignore */ comment inside the import() call to suppress this warning.

尝试点击菜单进入相应页面,报error:

TypeError: Failed to resolve module specifier '@/views/eat/apple/index.vue'

使用import.meta.glob解决。文档:glob导入 功能 | Vite 官方中文文档 (vitejs.dev)

首先通过glob声明需要动态导入模块的匹配路径(懒加载),之后调用即可。

const modules=import.meta.glob('/src/views/*/*/*.vue')

...

component: modules[`/src/${child.component}`]

参考: vue3+vite2警告提示The above dynamic import cannot be analyzed by vite问题,vite中import动态引入_云秒有个程序员-CSDN博客 和  vite 动态 import 引入打包报错解决方案 - 会写代码的赖先生 - 博客园 (cnblogs.com)

注意!glob中的路径不能使用别名!文档:该 Glob 模式会被当成导入标识符:必须是相对路径(以 ./ 开头)或绝对路径(以 / 开头,相对于项目根目录解析)。

const modules=import.meta.glob('@/views/*/*/*.vue')会报错,提醒必须以"." 或 "/"开头。

[vite] Internal server error: Invalid glob import syntax: pattern must start with "." or "/" (relative to project root)

component: modules[`@/${child.component}`],点击菜单项会报错,没能成功获取到组件:

vue-router.esm-bundler.js:72 [Vue Router warn]: Component "default" in record with path "/device/terminal" is not a valid component. Received "undefined".

by 莫得感情踩坑机(限定)

 类似资料: