升级pinia3和vue-router5

解决了 pinia3 defineStore 单对象写法运行时报错、vue-router5 next() 回调废弃警告两个问题。

$Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
JEECG 2026-07-11 21:58:44 +08:00
parent 20d46e1443
commit f390fe58bb
18 changed files with 3927 additions and 3870 deletions

View File

@ -33,6 +33,10 @@ package.json (vite / vite-plugin-pwa 版本升级)
- Vite 官方迁移指南v7→v8https://cn.vite.dev/guide/migration
- Vite CHANGELOGhttps://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md
## 依赖版本更新稳妥模式pnpm update
在保持所有主版本号不变的前提下,用 `pnpm update` 把依赖升级到各自 semver 范围内的最新小版本/补丁版本(例如 vue 3.5.27→3.5.39、vue-router 4.5.1→4.6.4、axios 1.13.2→1.18.1、dayjs/qs/sortablejs 等补丁更新),未改动 pinia/vue-router/vue 的主版本。升级后 `pnpm build``pnpm dev` 均验证通过。
## 迁移说明要点v7→v8
Vite8 底层由 Rollup+esbuild 切换为 Rolldown+Oxc核心变化
@ -63,3 +67,45 @@ v6→v7 迁移内容项目此前已完成升级(升级 Vite8 前项目已在 v
| 格式嗅探移除 | 待观察 | 静态分析+构建通过未发现问题,需长期使用中留意 |
-- author:zhangdaiscott ---date:20260711 ---
-- author:zhangdaiscott ---date:20260711--for: pinia 升级到 3.x、vue-router 升级到 5.x ---
## 修改内容
- pinia: 2.1.7 → ^3.0.4
- vue-router: ^4.6.4 → ^5.1.0
- vue / @vue/compiler-sfc 已在此前的补丁更新中满足 vue-router5 所需的 `^3.5.34` peer 依赖,无需再单独升级
## 解决的问题
1. 解决了 pinia 3 移除 `defineStore({ id: 'xxx', ... })` 单对象写法后,项目中 11 个 store 文件在运行时抛出 `Cannot destructure property 'state' of 'options' as it is undefined` 报错、导致应用启动白屏的问题。已全部改为 `defineStore('xxx', { ... })` 新写法。
## 验证结果
- `pnpm build` 构建成功
- `pnpm dev` + 无头浏览器Playwright实测页面正常渲染登录页无 pageerror/console.error
- 涉及的 11 个 store 文件user.ts、permission.ts、multipleTab.ts、lock.ts、locale.ts、errorLog.ts、defIndex.ts、app.ts、cgform/enhance.ts、cgform/cgformState.ts、cgform/share/shareStore.ts
-- author:zhangdaiscott ---date:20260711 ---
-- author:zhangdaiscott ---date:20260711--for: 修复 vue-router 导航守卫 next() 回调废弃警告 ---
## 修改内容
将以下文件的导航守卫从 `next()` 回调风格改为返回值风格vue-router 5 推荐写法,`next()` 回调已废弃):
- src/router/index.ts
- src/router/guard/permissionGuard.ts
- src/router/guard/paramMenuGuard.ts
- src/views/super/online/cgform/share/route/index.tsrouterBeforeEach
## 解决的问题
解决了浏览器控制台反复出现的 `[Vue Router warn]: The next() callback in navigation guards is deprecated. Return the value instead of calling next(value)` 警告。逐条改写时保持了原有分支逻辑不变next(x) → return xnext() → return truenext(redirectData) → return redirectData
## 验证结果
- `pnpm build` 构建成功
- `pnpm dev` + 无头浏览器Playwright实测登录页正常渲染控制台无 next() 警告、无 pageerror/console.error
-- author:zhangdaiscott ---date:20260711 ---

View File

@ -23,34 +23,34 @@
"husky:install": "husky install"
},
"dependencies": {
"@jeecg/aiflow":"3.9.2-beta",
"@logicflow/core": "^2.1.2",
"@logicflow/extension": "^2.1.4",
"@logicflow/vue-node-registry": "^1.1.3",
"@jeecg/aiflow": "3.9.2-beta",
"@logicflow/core": "^2.2.4",
"@logicflow/extension": "^2.3.0",
"@logicflow/vue-node-registry": "^1.2.4",
"@iconify/iconify": "^3.1.1",
"@ant-design/colors": "^7.2.1",
"@ant-design/icons-vue": "^7.0.1",
"@vue/shared": "^3.5.22",
"@vue/shared": "^3.5.39",
"@vueuse/core": "^10.11.1",
"@tinymce/tinymce-vue": "4.0.7",
"@zxcvbn-ts/core": "^3.0.4",
"ant-design-vue": "^4.2.6",
"axios": "^1.12.2",
"axios": "^1.18.1",
"@vant/area-data": "^1.5.2",
"clipboard": "^2.0.11",
"codemirror": "^5.65.20",
"codemirror": "^5.65.21",
"cron-parser": "^4.9.0",
"cropperjs": "^1.6.2",
"crypto-js": "^4.2.0",
"dayjs": "^1.11.18",
"dayjs": "^1.11.21",
"dom-align": "^1.12.4",
"echarts": "^5.6.0",
"emoji-mart-vue-fast": "^15.0.5",
"enquire.js": "^2.1.6",
"intro.js": "^7.2.0",
"lodash-es": "^4.17.21",
"lodash-es": "^4.18.1",
"lodash.get": "^4.4.2",
"markdown-it": "^14.1.0",
"markdown-it": "^14.3.0",
"markdown-it-link-attributes": "^4.0.1",
"event-source-polyfill": "^1.0.31",
"highlight.js": "^11.11.1",
@ -59,24 +59,24 @@
"mockjs": "^1.1.0",
"nprogress": "^0.2.0",
"path-to-regexp": "^6.3.0",
"pinia": "2.1.7",
"pinia": "^3.0.4",
"print-js": "^1.6.0",
"pinyin-pro": "^3.27.0",
"qs": "^6.14.0",
"pinyin-pro": "^3.28.1",
"qs": "^6.15.3",
"qrcode": "^1.5.4",
"resize-observer-polyfill": "^1.5.1",
"showdown": "^2.1.0",
"sortablejs": "^1.15.6",
"swagger-ui-dist": "^5.29.3",
"sortablejs": "^1.15.7",
"swagger-ui-dist": "^5.32.8",
"tinymce": "6.6.2",
"vditor": "^3.11.2",
"vue": "^3.5.22",
"vue": "^3.5.39",
"vue-cropper": "^0.6.5",
"vue-cropperjs": "^5.0.0",
"vue-i18n": "^9.14.5",
"vue-infinite-scroll": "^2.0.2",
"vue-print-nb-jeecg": "^1.0.13",
"vue-router": "^4.5.1",
"vue-router": "^5.1.0",
"vue-types": "^5.1.3",
"vuedraggable": "^4.1.0",
"vxe-table": "4.13.31",
@ -85,96 +85,96 @@
"xe-utils": "3.5.26",
"xss": "^1.0.15",
"vue-grid-layout-v3": "^3.1.2",
"lunar-javascript": "^1.7.5",
"lunar-javascript": "^1.7.7",
"perfect-scrollbar": "^1.5.6",
"vue-color": "^3.3.3"
},
"devDependencies": {
"@commitlint/cli": "^18.6.1",
"@commitlint/config-conventional": "^18.6.3",
"@iconify/json": "^2.2.394",
"@iconify/json": "^2.2.498",
"@purge-icons/generated": "^0.10.0",
"unplugin-icons": "^0.22.0",
"@types/codemirror": "^5.60.16",
"@types/codemirror": "^5.60.17",
"@types/crypto-js": "^4.2.2",
"@types/fs-extra": "^11.0.4",
"@types/inquirer": "^9.0.9",
"@types/inquirer": "^9.0.10",
"@types/intro.js": "^5.1.5",
"@types/jest": "^29.5.14",
"@types/lodash-es": "^4.17.12",
"@types/mockjs": "^1.0.10",
"@types/node": "^20.19.20",
"@types/node": "^20.19.43",
"@types/nprogress": "^0.2.3",
"@types/qrcode": "^1.5.5",
"@types/qs": "^6.14.0",
"@types/qrcode": "^1.5.6",
"@types/qs": "^6.15.1",
"@types/pinyin": "^2.10.2",
"@types/showdown": "^2.0.6",
"@types/sortablejs": "^1.15.8",
"@types/sortablejs": "^1.15.9",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.21.0",
"@vitejs/plugin-vue": "^6.0.6",
"@vitejs/plugin-vue-jsx": "^5.1.5",
"@vue/compiler-sfc": "^3.5.22",
"@vue/test-utils": "^2.4.6",
"autoprefixer": "^10.4.21",
"commitizen": "^4.3.1",
"@vitejs/plugin-vue": "^6.0.7",
"@vitejs/plugin-vue-jsx": "^5.1.6",
"@vue/compiler-sfc": "^3.5.39",
"@vue/test-utils": "^2.4.11",
"autoprefixer": "^10.5.2",
"commitizen": "^4.3.2",
"conventional-changelog-cli": "^4.1.0",
"cross-env": "^7.0.3",
"cz-git": "^1.12.0",
"czg": "^1.12.0",
"cz-git": "^1.13.1",
"czg": "^1.13.1",
"dotenv": "^16.6.1",
"eslint": "^8.57.1",
"eslint-config-prettier": "^9.1.2",
"eslint-define-config": "^2.1.0",
"eslint-plugin-jest": "^27.9.0",
"eslint-plugin-prettier": "^5.5.4",
"eslint-plugin-prettier": "^5.5.6",
"eslint-plugin-vue": "^9.33.0",
"esno": "^4.8.0",
"fs-extra": "^11.3.2",
"fs-extra": "^11.3.6",
"http-server": "^14.1.1",
"husky": "^8.0.3",
"inquirer": "^9.3.8",
"is-ci": "^3.0.1",
"jest": "^29.7.0",
"less": "^4.4.2",
"less": "^4.6.7",
"lint-staged": "15.2.2",
"npm-run-all": "^4.1.5",
"picocolors": "^1.1.1",
"postcss": "^8.5.6",
"postcss-html": "^1.8.0",
"postcss": "^8.5.16",
"postcss-html": "^1.8.1",
"postcss-less": "^6.0.0",
"prettier": "^3.6.2",
"prettier": "^3.9.5",
"pretty-quick": "^4.2.2",
"rimraf": "^5.0.10",
"rollup": "4.52.5",
"rollup-plugin-visualizer": "5.14.0",
"stylelint": "^16.25.0",
"stylelint": "^16.26.1",
"stylelint-config-prettier": "^9.0.5",
"stylelint-config-recommended": "^14.0.1",
"stylelint-config-recommended-vue": "^1.6.1",
"stylelint-config-standard": "^36.0.1",
"stylelint-order": "^6.0.4",
"ts-jest": "^29.4.4",
"ts-jest": "^29.4.11",
"ts-node": "^10.9.2",
"typescript": "^5.9.3",
"unplugin-vue-components": "~0.24.1",
"vite": "^8.1.4",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-html": "^3.2.2",
"vite-plugin-mkcert": "^1.17.9",
"vite-plugin-mkcert": "^1.17.12",
"vite-plugin-mock": "^2.9.8",
"vite-plugin-optimize-persist": "^0.1.2",
"vite-plugin-package-config": "^0.1.1",
"vite-plugin-purge-icons": "^0.10.0",
"vite-plugin-svg-icons": "^2.0.1",
"vite-plugin-pwa": "^1.3.0",
"workbox-window": "^7.3.0",
"workbox-window": "^7.4.1",
"vite-plugin-qiankun": "^1.0.15",
"vite-plugin-vue-setup-extend-plus": "^0.1.0",
"unocss": "^66.6.8",
"unocss": "^66.7.5",
"vue-eslint-parser": "^9.4.3",
"vue-tsc": "^1.8.27",
"dingtalk-jsapi": "^3.2.0",
"dingtalk-jsapi": "^3.2.9",
"big.js": "^6.2.2",
"tinycolor2": "1.6.0"
},

File diff suppressed because it is too large Load Diff

View File

@ -8,16 +8,14 @@ import { usePermissionStoreWithOut } from '/@/store/modules/permission';
export function createParamMenuGuard(router: Router) {
const permissionStore = usePermissionStoreWithOut();
router.beforeEach(async (to, _, next) => {
router.beforeEach(async (to, _) => {
// filter no name route
if (!to.name) {
next();
return;
}
// menu has been built.
if (!permissionStore.getIsDynamicAddedRoute) {
next();
return;
}
@ -28,8 +26,6 @@ export function createParamMenuGuard(router: Router) {
menus = permissionStore.getFrontMenuList;
}
menus.forEach((item) => configureDynamicParamsMenu(item, to.params));
next();
});
}

View File

@ -36,7 +36,7 @@ export function createPermissionGuard(router: Router) {
//
let homePathJumpCount = 0;
router.beforeEach(async (to, from, next) => {
router.beforeEach(async (to, from) => {
if (
// #6861
homePathJumpCount < 1 &&
@ -46,8 +46,7 @@ export function createPermissionGuard(router: Router) {
userStore.getUserInfo.homePath !== PageEnum.BASE_HOME
) {
homePathJumpCount++;
next(userStore.getUserInfo.homePath);
return;
return userStore.getUserInfo.homePath;
}
const token = userStore.getToken;
@ -62,8 +61,7 @@ export function createPermissionGuard(router: Router) {
try {
if (!isSessionTimeout) {
next((to.query?.redirect as string) || '/');
return;
return (to.query?.redirect as string) || '/';
}
} catch {}
// : [issues/I5BG1I]vue3auth2------------
@ -74,19 +72,16 @@ export function createPermissionGuard(router: Router) {
if(to.query.tenantId){
setAuthCache(OAUTH2_THIRD_LOGIN_TENANT_ID,to.query.tenantId)
}
next({ path: OAUTH2_LOGIN_PAGE_PATH });
return;
return { path: OAUTH2_LOGIN_PAGE_PATH };
}
next();
return;
return true;
}
// token does not exist
if (!token) {
// You can access without permission. You need to set the routing meta.ignoreAuth to true
if (to.meta.ignoreAuth) {
next();
return;
return true;
}
// : [issues/I5BG1I]vue3 Auth2------------
@ -94,10 +89,10 @@ export function createPermissionGuard(router: Router) {
if (whitePathList.includes(to.path as PageEnum)) {
// loginOAuth2appOAuth2
if (to.path === LOGIN_PATH && isOAuth2AppEnv()) {
next({ path: OAUTH2_LOGIN_PAGE_PATH });
return { path: OAUTH2_LOGIN_PAGE_PATH };
} else {
//
next();
return true;
}
} else {
//---------------------------------------------------------
@ -139,8 +134,7 @@ export function createPermissionGuard(router: Router) {
};
}
next(redirectData);
return;
return redirectData;
}
//================================================
@ -148,17 +142,15 @@ export function createPermissionGuard(router: Router) {
if(isOAuth2AppEnv() && to.path.indexOf("/tenantId/") != -1){
// : TV360X-2958---
if (isOAuth2DingAppEnv()) {
next(OAUTH2_LOGIN_PAGE_PATH);
return OAUTH2_LOGIN_PAGE_PATH;
} else {
next(userStore.getUserInfo.homePath || PageEnum.BASE_HOME);
return userStore.getUserInfo.homePath || PageEnum.BASE_HOME;
}
return;
}
//================================================
// Jump to the 404 page after processing the login
if (from.path === LOGIN_PATH && to.name === PAGE_NOT_FOUND_NAME_404 && to.fullPath !== (userStore.getUserInfo.homePath || PageEnum.BASE_HOME)) {
next(userStore.getUserInfo.homePath || PageEnum.BASE_HOME);
return;
return userStore.getUserInfo.homePath || PageEnum.BASE_HOME;
}
// // get userinfo while last fetch time is empty
@ -176,8 +168,7 @@ export function createPermissionGuard(router: Router) {
userStore.setAllDictItemsByLocal();
}
if (permissionStore.getIsDynamicAddedRoute) {
next();
return;
return true;
}
//
@ -191,12 +182,12 @@ export function createPermissionGuard(router: Router) {
// : issues/7500vue-router4.5.0name:PageNotFound
if (to.name === PAGE_NOT_FOUND_NAME_404) {
// fullPath404
next({ path: to.fullPath, replace: true, query: to.query });
return { path: to.fullPath, replace: true, query: to.query };
} else {
const redirectPath = (from.query.redirect || to.path) as string;
const redirect = decodeURIComponent(redirectPath);
const nextData = to.path === redirect ? { ...to, replace: true } : { path: redirect };
next(nextData);
return nextData;
}
});
}

View File

@ -28,13 +28,11 @@ export function createRouter() {
)
// TODO QQYUN-4517
// @ts-ignore
router.beforeEach(async (to, from, next) => {
router.beforeEach(async (to, from) => {
//console.group('QQYUN-4517beforeEach');
//console.warn('from', from);
//console.warn('to', to);
//console.groupEnd();
next();
});
}

View File

@ -28,8 +28,7 @@ interface AppState {
mainAppProps: MainAppProps,
}
let timeId: TimeoutHandle;
export const useAppStore = defineStore({
id: 'app',
export const useAppStore = defineStore('app', {
state: (): AppState => ({
darkMode: undefined,
pageLoading: false,

View File

@ -9,8 +9,7 @@ interface DefIndexState {
component: string
}
export const useDefIndexStore = defineStore({
id: 'defIndex',
export const useDefIndexStore = defineStore('defIndex', {
state: (): DefIndexState => ({
url: '',
component: '',

View File

@ -13,8 +13,7 @@ export interface ErrorLogState {
errorLogListCount: number;
}
export const useErrorLogStore = defineStore({
id: 'app-error-log',
export const useErrorLogStore = defineStore('app-error-log', {
state: (): ErrorLogState => ({
errorLogInfoList: null,
errorLogListCount: 0,

View File

@ -20,8 +20,7 @@ interface LocaleState {
appMainPth: string
}
export const useLocaleStore = defineStore({
id: 'app-locale',
export const useLocaleStore = defineStore('app-locale', {
state: (): LocaleState => ({
localInfo: lsLocaleSetting,
pathTitleMap: {},

View File

@ -10,8 +10,7 @@ interface LockState {
lockInfo: Nullable<LockInfo>;
}
export const useLockStore = defineStore({
id: 'app-lock',
export const useLockStore = defineStore('app-lock', {
state: (): LockState => ({
lockInfo: Persistent.getLocal(LOCK_INFO_KEY),
}),

View File

@ -87,8 +87,7 @@ function getMatchingRoute(menus, path) {
const cacheTab = projectSetting.multiTabsSetting.cache;
export const useMultipleTabStore = defineStore({
id: 'app-multiple-tab',
export const useMultipleTabStore = defineStore('app-multiple-tab', {
state: (): MultipleTabState => ({
// Tabs that need to be cached
cacheTabList: new Set(),

View File

@ -56,8 +56,7 @@ interface PermissionState {
// online
onlineSubTableAuthMap: object;
}
export const usePermissionStore = defineStore({
id: 'app-permission',
export const usePermissionStore = defineStore('app-permission', {
state: (): PermissionState => ({
permCodeList: [],
// Whether the route has been dynamically added

View File

@ -35,8 +35,7 @@ interface UserState {
loginInfo?: Nullable<LoginInfo>;
}
export const useUserStore = defineStore({
id: 'app-user',
export const useUserStore = defineStore('app-user', {
state: (): UserState => ({
//
userInfo: null,

View File

@ -65,7 +65,7 @@ export const SHARE_LOGIN_ROUTE: RouteRecordRaw = {
// Online
const ONLINE_CGFORM_SHARE = '/online/cgform/share';
export async function routerBeforeEach(to: any, _from: any, next: any) {
export async function routerBeforeEach(to: any, _from: any) {
//
if (to.path === PageEnum.BASE_LOGIN) {
// redirect
@ -86,14 +86,12 @@ export async function routerBeforeEach(to: any, _from: any, next: any) {
// online
if (redirect) {
redirect = redirect.split('?')[0];
next({
return {
name: SHARE_LOGIN__ROUTER_NAME,
query: {
redirect: encodeURIComponent(redirect),
}
});
return;
};
}
}
next();
}

View File

@ -11,8 +11,7 @@ interface StateType {
const userStore = useUserStoreWithOut()
export const useShareStore = defineStore({
id: 'online-cgform-share',
export const useShareStore = defineStore('online-cgform-share', {
state: (): StateType => ({
cgformRecord: null,
dataRecord: null,

View File

@ -6,8 +6,7 @@ interface CgformState {
changedTables: string[];
}
export const useCgformStore = defineStore({
id: 'cgform-state',
export const useCgformStore = defineStore('cgform-state', {
state: (): CgformState => ({
changedTables: [],
}),

View File

@ -9,8 +9,7 @@ interface EnhanceStore {
enhanceJs: Recordable;
}
export const useEnhanceStore = defineStore({
id: 'online-cgform-enhance',
export const useEnhanceStore = defineStore('online-cgform-enhance', {
state: (): EnhanceStore => ({
enhanceJs: {},
}),