开淘宝店和做网站有什么区别,建设网站方法,网络营销课程总结1500字,咖啡网页设计代码背景描述
升级的项目本来是vue2的项目#xff0c;先升级成vue3#xff0c;这个过程相关的问题都被决绝#xff0c;当时状态管理使用的还是vuex4.x版本。
后面发现变成复杂模块时#xff0c;后续再对复杂模块的功能进行迭代时#xff0c;由于js的弱类型#xff0c;改动时…背景描述
升级的项目本来是vue2的项目先升级成vue3这个过程相关的问题都被决绝当时状态管理使用的还是vuex4.x版本。
后面发现变成复杂模块时后续再对复杂模块的功能进行迭代时由于js的弱类型改动时比较容易出现问题而且接口之间没有类型约束导致改动时需要对比接口数据再重新思考整个逻辑导致维护成本提升。
后面引入TS的过程中想将 vuex顺便替换成vue3种官方推荐的 pinia。按照pinia官方的文档改动很容易大概有这个几个地方
1. 重构store
pinia编写store时采用扁平化的方式直接将原有的vuex中state,getter,action迁移其中mutations也直接写成actions因为pinia action支持同步和异步这样大大减少vuex中的概念确认。
2. 替换vue 组件中对store的使用
主要是以下几种方式 ● 通过 s t o r e . c o m m i t 或者 store.commit 或者 store.commit或者store.dispatch使用。 ● 通过mapState,mapActions等使用 pinia 官方同样提供了支持直接替换就好。
升级的问题
看似没有问题
本地dev模式下由于是边改边看的而且未完成迁移前vuex和pinia并存项目都是正常的整体迁移完后除了肉眼改动错误的地方一切都是正常的。全部移除vuex的时候突然出现问题
Uncaught ReferenceError: Cannot access useUserStore before initialization
at main.vue这个代码中有如下代码 methods: {...mapActions(useAppStore, [setLocal, setParentMenu, setUserServerData, setUserServerCascadeData]),...mapActions(useUserStore, [setUnReadMsgCount]),searchFileOpen(params) {this.$bus.emit(on-search-file-open, params)},}就是store的action映射到组件。查询资料官方给出的解释是 pinia实例没有挂载。 实际项目中导致的这种问题是在 router定义文件中使用main.vue作为导航的主组件也就是component参数。
import * as Vue from vue
import Main from /view/main
import FullScreenMain from /view/main/full-screen-main.vue
import SliderMain from /view/main/slider-main.vue
import Blank from /blank.vueexport default [{path: /,name: rootPath,redirect: /index,},{path: /blank,name: Blank,component: Blank,},{path: /index,name: index,redirect: /script/owner/-1,parentMenu: 1,meta: {icon: ios-navigate,title: 工作空间,launchItemName: script,},component: Main,children: [{path: /script/:scriptType/:scriptId,name: scriptIndex,meta: {parentMenu: 1,icon: document-text,title: 工作空间,launchItemName: script,},component: () import(/view/script-manage/script-list.vue),},]}
]
这个路由定义在createRouter中使用于是根据官方的思路应该是创建路由时加载了组件而组件中使用的mapActions 方法但是此时整个vue实例没有挂载导致pinia未初始化从而引发useUserStore 函数不可用问题。
解决办法既然是创建时机的问题那么在路由中加载main组件时使用异步加载就好这样等整个vue实例挂载后再去访问页面肯定可以的。在上面的router定义中改动如下
const Main () import(/view/main)
const FullScreenMain () import(/view/main/full-screen-main.vue)
const SliderMain () import(/view/main/slider-main.vue)xxx 省然后 npm run dev 项目正常启动功能正常。
惊慌的上线构建发布
在上述问题都解决后项目发布到准线上运行在发布流程完成后开心的打开新页面一看我艹页面的菜单呢。怎么都没有了急忙打开控制台想要看到红色的xxx可一个都没有。顿时慌了发生了什么
再次在本地删掉node_modules再次启动项目本地还是正常。同样线上重新构建发现依然没有菜单也没有任何错误。
接下来怀疑环境线上构建是node 18.15.0本地是20.10。尝试指定线上node版本由于太高构建工具不支持只能调低本地版本切换成18.15.0后dev模式启动依然正常瞬间感觉不该搞升级吃力还出了问题但是没办法得继续解决。
解析来本地模拟线上环境使用同样的构建命令使用本地nginx作为静态服务器折腾半天后本地终于能启动出现了线上相同的问题。
接下来排查菜单消失的原因。代码中大量使用了动态菜单即对比路由定义上的元数据和后端接口的权限信息动态的构建路由和菜单组件有一个工具方法
export const getFirstLevelMenuByRouter (list) {const res []const parentChildrenList []for (let i 0; i list.length; i) {if (list[i].hasOwnProperty(component) list[i].component list[i].component.name Main) {parentChildrenList.push(list[i])}}forEach(parentChildrenList, (item) {if (item.meta !item.meta.hideInMenu) {const obj {icon: (item.meta item.meta.icon) || ,name: item.name,meta: item.meta,parentMenu: item.parentMenu,path: item.path,}res.push(obj)}})return res
}这个方法生成一级菜单对组件进行了名称判断。然后通过打日志发现新版本经过这个方法后返回空数组即 判断 component.name‘Main’ 失效了。然后突然想起来为决绝pinia异步加载的问题Main改成了 const Main () import(‘/view/main’) 这种方式名称变了自然匹配不上。 该怎么解决
const Main defineAsyncComponent(() import(/view/main))
Main.name Main
const FullScreenMain defineAsyncComponent(() import(/view/main/full-screen-main.vue))
FullScreenMain.name FullScreenMain
const SliderMain defineAsyncComponent(() import(/view/main/slider-main.vue))
SliderMain.name SliderMain对于有问题的组件全部改成异步并指定名称。
结论
● 使用异步组件解决pinia初始化晚导致如果在路由中引入的组件使用pinia函数报错问题。 ● 使用 defineAsyncComponent 定义异步组件并指定名称避免业务中对组件的名称进行了判断。
其它
尝试不使用异步组件
在线上构建问题后代码中去掉了异步加载路由组件的方式这时候必然出现 pinia中useXXStore未初始化的问题尝试去掉mapState,mapAction采用setup函数配合的方式出现如下问题 vue ReferenceError: Cannot access ‘Main’ before initialization 这叫莫名其妙了但是我知道肯定是因为pinia的原因也即是在Router中使用同步组件而组件中使用了pinia函数的原因但是这错误很诡异。这种方法行不通。
未解之谜
在初步使用异步import后使用dev 模式本地正常线上异常这说明dev模式和build 模式存在差异但是具体是什么没有细究。