当前位置: 首页 > news >正文

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的项目&#xff0c;先升级成vue3&#xff0c;这个过程相关的问题都被决绝&#xff0c;当时状态管理使用的还是vuex4.x版本。 后面发现变成复杂模块时&#xff0c;后续再对复杂模块的功能进行迭代时&#xff0c;由于js的弱类型&#xff0c;改动时…...

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. 关键词 关键词&#xff1a; C 字符串处理 分割字符串 连接字符串 跨平台 应用场景&#xff1a; 有些重要信息需要保密&#xff0c;比如手机号、邮箱等&#xff0c;如何在不影响用户阅读的情况下…...

【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文档中特定文本内容

工作任务&#xff1a;PDF文档中有资料来源这一行&#xff0c;比如&#xff1a; 资料来源&#xff1a;moomoo tech、The Information、Bloomberg、Reuters&#xff0c;浙商证券研究所 数据来源&#xff1a;CSDN、浙商证券研究所 数据来源&#xff1a;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作为缓存存储时&#xff0c;合理配置RedisTemplate是确保数据正确存储和检索的关键。本文将通过对比分析一段初始存在问题的Redis配置代码及其修正后的版本&#xff0c;探讨如何正确处理Redis键前缀&#xff0c;以避免清理缓存时遇到的问题。…...

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

文章链接&#xff1a;15后端开发连接外部数据源&#xff0c;实现在ecology系统中查询其他异构系统数据库得示例和源码...

弹幕逆向signature、a_bogus

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 本文章未经许可禁止转载&a…...

jEasyUI 使用标记创建树形菜单

jEasyUI 使用标记创建树形菜单 jEasyUI 是一个基于 jQuery 的用户界面插件库&#xff0c;它提供了一系列的组件&#xff0c;用于快速构建网页用户界面。其中&#xff0c;树形菜单&#xff08;Tree Menu&#xff09;是 jEasyUI 提供的一个非常实用的组件&#xff0c;它可以帮助…...

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个希腊字母学习

名词解释 在数学中&#xff0c;我们把∑作为求和符号使用&#xff0c;用小写字母σ&#xff0c;表示标准差。 ∑符号表示求和&#xff0c;读音为sigma&#xff0c;英文意思为Sum&#xff0c;Summation&#xff0c;汉语意思为“和”“总和”。 例1 公式使用说明&#xff1a;…...

【C语言】assert.h——断言

文章目录 主要内容调试和发布模式使用示例用法总结与注意事项 断言是一种用于在程序执行过程中进行调试的工具&#xff0c;能够帮助开发者验证程序的某些假设是否为真。如果断言失败&#xff0c;程序会终止&#xff0c;并输出一个错误消息&#xff0c;通常包含出错的文件名和行…...

HTML静态网页成品作业(HTML+CSS)—— 零食商城网页(1个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有1个页面。 二、作品演示 三、代…...

虚函数机制-动态绑定的应用

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

MOS开关电路应用于降低静态功耗

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

【每日刷题】Day65

【每日刷题】Day65 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. LCR 175. 计算二叉树的深度 - 力扣&#xff08;LeetCode&#xff09; 2. 序列找数_牛客题霸_牛客网…...

Oracle数据库连接并访问Microsoft SQL Server数据库

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

C++实现分布式网络通信框架RPC(3)--rpc调用端

目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中&#xff0c;我们已经大致实现了rpc服务端的各项功能代…...

DockerHub与私有镜像仓库在容器化中的应用与管理

哈喽&#xff0c;大家好&#xff0c;我是左手python&#xff01; Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库&#xff0c;用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

聊聊 Pulsar:Producer 源码解析

一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台&#xff0c;以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中&#xff0c;Producer&#xff08;生产者&#xff09; 是连接客户端应用与消息队列的第一步。生产者…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢

随着互联网技术的飞速发展&#xff0c;消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁&#xff0c;不仅优化了客户体验&#xff0c;还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用&#xff0c;并…...

Python实现prophet 理论及参数优化

文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候&#xff0c;写过一篇简单实现&#xff0c;后期随着对该模型的深入研究&#xff0c;本次记录涉及到prophet 的公式以及参数调优&#xff0c;从公式可以更直观…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

3403. 从盒子中找出字典序最大的字符串 I

3403. 从盒子中找出字典序最大的字符串 I 题目链接&#xff1a;3403. 从盒子中找出字典序最大的字符串 I 代码如下&#xff1a; class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

浅谈不同二分算法的查找情况

二分算法原理比较简单&#xff0c;但是实际的算法模板却有很多&#xff0c;这一切都源于二分查找问题中的复杂情况和二分算法的边界处理&#xff0c;以下是博主对一些二分算法查找的情况分析。 需要说明的是&#xff0c;以下二分算法都是基于有序序列为升序有序的情况&#xf…...