vuex4.x 升级pinia,router 中使用同步组件导致项目启动失败
背景描述
升级的项目本来是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.vue'export 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 模式存在差异,但是具体是什么,没有细究。
相关文章:
vuex4.x 升级pinia,router 中使用同步组件导致项目启动失败
背景描述 升级的项目本来是vue2的项目,先升级成vue3,这个过程相关的问题都被决绝,当时状态管理使用的还是vuex4.x版本。 后面发现变成复杂模块时,后续再对复杂模块的功能进行迭代时,由于js的弱类型,改动时…...

0. 云原生之基于乌班图远程开发
云原生专栏大纲 文章目录 安装乌班图配置静态IP重置root密码开启root远程登录开启远程SSH访问安装docker安装docker-compose安装Edge浏览器安装搜狗输入法安装TeamViewer安装虚拟显示器安装JDK安装maven安装vscodevscode插件安装VSCode配置maven、git、jdk、自动报错vscode快捷…...
C++ 字符串处理5-手机号邮箱如何脱敏处理
1. 关键词2. strutil.h3. strutil.cpp4. 测试代码5. 运行结果6. 源码地址 1. 关键词 关键词: C 字符串处理 分割字符串 连接字符串 跨平台 应用场景: 有些重要信息需要保密,比如手机号、邮箱等,如何在不影响用户阅读的情况下…...
【lesson8】云备份服务端完整版代码
文章目录 util.hppconfig.hpphot.hppdata.hppserver.hppserver.ccMakefilecloud.conf util.hpp #pragma once #include <iostream> #include <fstream> #include <string> #include <vector> #include <sys/stat.h> #include <unistd.h> …...

AI办公自动化:kimi批量搜索提取PDF文档中特定文本内容
工作任务:PDF文档中有资料来源这一行,比如: 资料来源:moomoo tech、The Information、Bloomberg、Reuters,浙商证券研究所 数据来源:CSDN、浙商证券研究所 数据来源:CSDN、arXiv、浙商证券研…...

基于C#开发web网页管理系统模板流程-总集篇
第一篇 基于C#开发web网页管理系统模板流程-登录界面和主界面_c#的网页编程-CSDN博客 第二篇 基于C#开发web网页管理系统模板流程-主界面管理员录入和编辑功能完善_c#网页设计-CSDN博客 第三篇 基于C#开发web网页管理系统模板流程-主界面管理员入库和出库功能完善_c#web程序设计…...

什么是DMZ?路由器上如何使用DMZ?
文章目录 📖 介绍 📖🏡 演示环境 🏡📒 DMZ 📒🚀 DMZ的应用场景💡 路由器设置DMZ🎈 注意事项 🎈⚓️ 相关链接 ⚓️📖 介绍 📖 在网络管理中,DMZ(Demilitarized Zone,隔离区)是一个特殊的网络区域,常用于将公共访问和内部网络隔离开来。DMZ功能允许…...
【bugfix】解决Redis缓存键清理问题
前言 在Spring Boot应用中集成Redis作为缓存存储时,合理配置RedisTemplate是确保数据正确存储和检索的关键。本文将通过对比分析一段初始存在问题的Redis配置代码及其修正后的版本,探讨如何正确处理Redis键前缀,以避免清理缓存时遇到的问题。…...

泛微开发修炼之旅--15后端开发连接外部数据源,实现在ecology系统中查询其他异构系统数据库得示例和源码
文章链接:15后端开发连接外部数据源,实现在ecology系统中查询其他异构系统数据库得示例和源码...

弹幕逆向signature、a_bogus
声明 本文章中所有内容仅供学习交流使用,不用于其他任何目的,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关! 本文章未经许可禁止转载&a…...
jEasyUI 使用标记创建树形菜单
jEasyUI 使用标记创建树形菜单 jEasyUI 是一个基于 jQuery 的用户界面插件库,它提供了一系列的组件,用于快速构建网页用户界面。其中,树形菜单(Tree Menu)是 jEasyUI 提供的一个非常实用的组件,它可以帮助…...
IT人的拖延——拖是因为不想离开“舒适区”?
人都是求“稳”的,在一个区域内呆了很久,也很舒适了,如果冒险离开进入未知的区域,万一结果不好怎么办?万一自己不适合怎么办?万一这个区域有着自己难以忍受的东西怎么办?这些对未知区域的恐惧感让我们在面对应该要做的事情时,不自觉地又拖延了起来。比如,我们在面临需…...

JUnit 5学习笔记
JUnit 5 学习笔记 1.JUnit5的改变2.JUnit5常用注解及测试2.1 DisplayName/Disabled/BeforeEach/AfterEach/BeforeAll/AfterAll2.2 Timeout2.3 RepeatedTest 3.断言3.1 简单断言3.2 数组断言3.3 组合断言3.4 异常断言3.5 超时断言3.6 快速失败 4.前置条件5.嵌套测试6.参数化测试…...

西格玛 ------ 第18个希腊字母学习
名词解释 在数学中,我们把∑作为求和符号使用,用小写字母σ,表示标准差。 ∑符号表示求和,读音为sigma,英文意思为Sum,Summation,汉语意思为“和”“总和”。 例1 公式使用说明:…...
【C语言】assert.h——断言
文章目录 主要内容调试和发布模式使用示例用法总结与注意事项 断言是一种用于在程序执行过程中进行调试的工具,能够帮助开发者验证程序的某些假设是否为真。如果断言失败,程序会终止,并输出一个错误消息,通常包含出错的文件名和行…...

HTML静态网页成品作业(HTML+CSS)—— 零食商城网页(1个页面)
🎉不定期分享源码,关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 🏷️本套采用HTMLCSS,未使用Javacsript代码,共有1个页面。 二、作品演示 三、代…...

虚函数机制-动态绑定的应用
虚函数使得程序在运行的时候根据指针指向对象的类型来确定调用哪个函数。 下图中:都为静态绑定。因为在编译器就确定了可以调用的函数 此时当基类指针指向派生类对象时,因为没有virtual关键字,所以在编译阶段就根据指针类型确定了要指向的函…...

MOS开关电路应用于降低静态功耗
本文主要讲述MOS开关电路的应用,过了好久突然想整理一下,有错误的地方请多多指出,在做电池类产品,需要控制产品的静态功耗,即使让芯片进入休眠状态,依旧功率很大,所以在电路中加一组软开关,防止…...

【每日刷题】Day65
【每日刷题】Day65 🥕个人主页:开敲🍉 🔥所属专栏:每日刷题🍍 🌼文章目录🌼 1. LCR 175. 计算二叉树的深度 - 力扣(LeetCode) 2. 序列找数_牛客题霸_牛客网…...

Oracle数据库连接并访问Microsoft SQL Server数据库
Oracle数据库连接并访问Microsoft SQL Server数据库 说明: 1.实际开发中,Oracle数据库与SQLServer数据库之间可能需要相互进行访问,方便业务数据抽取,编写视图及表等操作。 2.SQLServer访问Oracle数据库配置相对较为简单&…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...

React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...

什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...

linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”
2025年#高考 将在近日拉开帷幕,#AI 监考一度冲上热搜。当AI深度融入高考,#时间同步 不再是辅助功能,而是决定AI监考系统成败的“生命线”。 AI亮相2025高考,40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕,江西、…...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...