feat: migrate from unplugin-vue-router to vue-router v5 (#563)

* feat: migrate from unplugin-vue-router to vue-router v5

* chore: update lock

* fix: resolve CI failures for vue-router v5 migration

- Fix ESLint import order in vite.config.ts
- Fix readonly routes type mismatch in src/main.ts by spreading routes array
- Upgrade vite to v7, vite-ssg to v28, beasties to v0.4, and other deps
- Update CI node matrix from [18.x, 20.x] to [20.x, 22.x]

* chore: upgrade vite-plugin-pwa and vitest

* fix: bump Node.js version to 22 for Iterator helpers support

vue-router v5 uses Iterator helpers (e.g. `seen.values().filter()`)
which require Node.js >= 22. Bump NODE_VERSION in netlify.toml from
20 to 22 to fix the Netlify build failure.
This commit is contained in:
云游君
2026-02-25 16:36:23 +08:00
committed by GitHub
parent abf64f7dd4
commit f648eecd1d
12 changed files with 2402 additions and 1435 deletions
+1 -1
View File
@@ -47,7 +47,7 @@ jobs:
strategy:
matrix:
node-version: [18.x, 20.x]
node-version: [20.x, 22.x]
os: [ubuntu-latest]
fail-fast: false
+1 -1
View File
@@ -3,7 +3,7 @@ publish = "dist"
command = "pnpm run build"
[build.environment]
NODE_VERSION = "20"
NODE_VERSION = "22"
[[redirects]]
from = "/*"
-1
View File
@@ -56,7 +56,6 @@
"unplugin-vue-components": "catalog:build",
"unplugin-vue-macros": "catalog:build",
"unplugin-vue-markdown": "catalog:build",
"unplugin-vue-router": "catalog:build",
"vite": "catalog:build",
"vite-bundle-visualizer": "catalog:build",
"vite-plugin-inspect": "catalog:build",
+2256 -1380
View File
File diff suppressed because it is too large Load Diff
+14 -15
View File
@@ -5,32 +5,31 @@ catalogs:
build:
'@intlify/unplugin-vue-i18n': ^6.0.5
'@shikijs/markdown-it': ^3.2.1
'@unocss/eslint-config': ^66.1.0-beta.7
'@vitejs/plugin-vue': ^5.2.3
beasties: ^0.2.0
'@unocss/eslint-config': ^66.6.0
'@vitejs/plugin-vue': ^6.0.4
beasties: ^0.4.1
markdown-it-link-attributes: ^4.0.1
rollup: ^4.37.0
shiki: ^3.2.1
unocss: ^66.1.0-beta.7
unocss: ^66.6.0
unplugin: ^2.2.2
unplugin-auto-import: ^19.1.2
unplugin-vue-components: ^28.4.1
unplugin-vue-macros: ^2.14.5
unplugin-vue-markdown: ^28.3.1
unplugin-vue-router: ^0.12.0
vite: ^6.2.3
vite: ^7.3.1
vite-bundle-visualizer: ^1.2.1
vite-plugin-inspect: ^11.0.0
vite-plugin-pwa: ^0.21.2
vite-plugin-pwa: ^1.2.0
vite-plugin-vue-devtools: ^7.7.2
vite-plugin-vue-layouts: ^0.11.0
vite-ssg: ^26.0.0
vite-ssg-sitemap: ^0.8.1
vite-ssg: ^28.3.0
vite-ssg-sitemap: ^0.10.0
dev:
'@antfu/eslint-config': ^4.11.0
'@iconify-json/carbon': ^1.2.8
'@vue-macros/volar': ^3.0.0-beta.7
'@vue-macros/volar': ^3.1.2
'@vue/test-utils': ^2.4.6
cypress: ^14.2.1
cypress-vite: ^1.6.0
@@ -42,18 +41,18 @@ catalogs:
simple-git-hooks: ^2.12.1
taze: ^19.0.2
typescript: ^5.8.2
vitest: ^3.0.9
vue-tsc: ^2.2.8
vitest: ^4.0.18
vue-tsc: ^3.2.4
frontend:
'@unhead/vue': ^2.0.2
'@unocss/reset': ^66.1.0-beta.7
'@vueuse/core': ^13.0.0
nprogress: ^0.2.0
pinia: ^3.0.1
vue: ^3.5.13
pinia: ^3.0.4
vue: ^3.5.28
vue-i18n: ^11.1.2
vue-router: ^4.5.0
vue-router: ^5.0.3
types:
'@types/markdown-it-link-attributes': ^3.0.5
+2 -3
View File
@@ -31,12 +31,10 @@ declare global {
const debouncedWatch: typeof import('@vueuse/core')['debouncedWatch']
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
const defineComponent: typeof import('vue')['defineComponent']
const defineLoader: typeof import('vue-router/auto')['defineLoader']
const definePage: typeof import('unplugin-vue-router/runtime')['definePage']
const definePage: typeof import('vue-router/experimental')['definePage']
const eagerComputed: typeof import('@vueuse/core')['eagerComputed']
const effectScope: typeof import('vue')['effectScope']
const extendRef: typeof import('@vueuse/core')['extendRef']
const getActiveHead: typeof import('@unhead/vue')['getActiveHead']
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const getCurrentScope: typeof import('vue')['getCurrentScope']
const h: typeof import('vue')['h']
@@ -346,6 +344,7 @@ declare module 'vue' {
readonly debouncedWatch: UnwrapRef<typeof import('@vueuse/core')['debouncedWatch']>
readonly defineAsyncComponent: UnwrapRef<typeof import('vue')['defineAsyncComponent']>
readonly defineComponent: UnwrapRef<typeof import('vue')['defineComponent']>
readonly definePage: UnwrapRef<typeof import('vue-router/experimental')['definePage']>
readonly eagerComputed: UnwrapRef<typeof import('@vueuse/core')['eagerComputed']>
readonly effectScope: UnwrapRef<typeof import('vue')['effectScope']>
readonly extendRef: UnwrapRef<typeof import('@vueuse/core')['extendRef']>
+1
View File
@@ -2,6 +2,7 @@
// @ts-nocheck
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
// biome-ignore lint: disable
export {}
/* prettier-ignore */
+1 -1
View File
@@ -13,7 +13,7 @@ import 'uno.css'
export const createApp = ViteSSG(
App,
{
routes: setupLayouts(routes),
routes: setupLayouts([...routes]),
base: import.meta.env.BASE_URL,
},
(ctx) => {
+121
View File
@@ -0,0 +1,121 @@
/* eslint-disable */
/* prettier-ignore */
// oxfmt-ignore
// @ts-nocheck
// noinspection ES6UnusedImports
// Generated by vue-router. !! DO NOT MODIFY THIS FILE !!
// It's recommended to commit this file.
// Make sure to add this file to your tsconfig.json file as an "includes" or "files" entry.
import type {
RouteRecordInfo,
ParamValue,
ParamValueOneOrMore,
ParamValueZeroOrMore,
ParamValueZeroOrOne,
} from 'vue-router'
declare module 'vue-router' {
interface TypesConfig {
ParamParsers: never
}
}
declare module 'vue-router/auto-routes' {
/**
* Route name map generated by vue-router
*/
export interface RouteNamedMap {
'/': RouteRecordInfo<
'/',
'/',
Record<never, never>,
Record<never, never>,
| never
>,
'/[...all]': RouteRecordInfo<
'/[...all]',
'/:all(.*)',
{ all: ParamValue<true> },
{ all: ParamValue<false> },
| never
>,
'/about': RouteRecordInfo<
'/about',
'/about',
Record<never, never>,
Record<never, never>,
| never
>,
'/hi/[name]': RouteRecordInfo<
'/hi/[name]',
'/hi/:name',
{ name: ParamValue<true> },
{ name: ParamValue<false> },
| never
>,
'/README': RouteRecordInfo<
'/README',
'/README',
Record<never, never>,
Record<never, never>,
| never
>,
}
/**
* Route file to route info map by vue-router.
* Used by the \`sfc-typed-router\` Volar plugin to automatically type \`useRoute()\`.
*
* Each key is a file path relative to the project root with 2 properties:
* - routes: union of route names of the possible routes when in this page (passed to useRoute<...>())
* - views: names of nested views (can be passed to <RouterView name="...">)
*
* @internal
*/
export interface _RouteFileInfoMap {
'src/pages/index.vue': {
routes:
| '/'
views:
| never
}
'src/pages/[...all].vue': {
routes:
| '/[...all]'
views:
| never
}
'src/pages/about.md': {
routes:
| '/about'
views:
| never
}
'src/pages/hi/[name].vue': {
routes:
| '/hi/[name]'
views:
| never
}
'src/pages/README.md': {
routes:
| '/README'
views:
| never
}
}
/**
* Get a union of possible route names in a certain route component file.
* Used by the \`sfc-typed-router\` Volar plugin to automatically type \`useRoute()\`.
*
* @internal
*/
export type _RouteNamesForFilePath<FilePath extends string> =
_RouteFileInfoMap extends Record<FilePath, infer Info>
? Info['routes']
: keyof RouteNamedMap
}
export {}
-27
View File
@@ -1,27 +0,0 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// Generated by unplugin-vue-router. ‼️ DO NOT MODIFY THIS FILE ‼️
// It's recommended to commit this file.
// Make sure to add this file to your tsconfig.json file as an "includes" or "files" entry.
declare module 'vue-router/auto-routes' {
import type {
RouteRecordInfo,
ParamValue,
ParamValueOneOrMore,
ParamValueZeroOrMore,
ParamValueZeroOrOne,
} from 'vue-router'
/**
* Route name map generated by unplugin-vue-router
*/
export interface RouteNamedMap {
'/': RouteRecordInfo<'/', '/', Record<never, never>, Record<never, never>>,
'/[...all]': RouteRecordInfo<'/[...all]', '/:all(.*)', { all: ParamValue<true> }, { all: ParamValue<false> }>,
'/about': RouteRecordInfo<'/about', '/about', Record<never, never>, Record<never, never>>,
'/hi/[name]': RouteRecordInfo<'/hi/[name]', '/hi/:name', { name: ParamValue<true> }, { name: ParamValue<false> }>,
'/README': RouteRecordInfo<'/README', '/README', Record<never, never>, Record<never, never>>,
}
}
+1 -2
View File
@@ -15,8 +15,7 @@
"vite/client",
"vite-plugin-vue-layouts/client",
"vite-plugin-pwa/client",
"unplugin-vue-macros/macros-global",
"unplugin-vue-router/client"
"unplugin-vue-macros/macros-global"
],
"allowJs": true,
"strict": true,
+4 -4
View File
@@ -9,13 +9,13 @@ import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import VueMacros from 'unplugin-vue-macros/vite'
import Markdown from 'unplugin-vue-markdown/vite'
import { VueRouterAutoImports } from 'unplugin-vue-router'
import VueRouter from 'unplugin-vue-router/vite'
import { defineConfig } from 'vite'
import { VitePWA } from 'vite-plugin-pwa'
import VueDevTools from 'vite-plugin-vue-devtools'
import Layouts from 'vite-plugin-vue-layouts'
import generateSitemap from 'vite-ssg-sitemap'
import { VueRouterAutoImports } from 'vue-router/unplugin'
import VueRouter from 'vue-router/vite'
import 'vitest/config'
export default defineConfig({
@@ -26,10 +26,10 @@ export default defineConfig({
},
plugins: [
// https://github.com/posva/unplugin-vue-router
// https://github.com/vuejs/router
VueRouter({
extensions: ['.vue', '.md'],
dts: 'src/typed-router.d.ts',
dts: 'src/route-map.d.ts',
}),
VueMacros({