From cac24b970603fdacfb6bd332f45dc18fc4252039 Mon Sep 17 00:00:00 2001
From: InsHomePgup <7328234@gmail.com>
Date: Tue, 9 Jan 2024 15:57:51 +0800
Subject: [PATCH] feat: Add support for file-based routing (#53)
---
package.json | 1 +
pnpm-lock.yaml | 91 +++++++++++++++++++++++++-
src/auto-imports.d.ts | 12 ++--
src/router/README.md | 4 ++
src/router/index.ts | 36 +----------
src/typed-router.d.ts | 144 ++++++++++++++++++++++++++++++++++++++++++
vite.config.ts | 12 +++-
7 files changed, 258 insertions(+), 42 deletions(-)
create mode 100644 src/router/README.md
create mode 100644 src/typed-router.d.ts
diff --git a/package.json b/package.json
index 3f55301f..97b785a3 100644
--- a/package.json
+++ b/package.json
@@ -60,6 +60,7 @@
"unocss": "^0.58.0",
"unplugin-auto-import": "^0.17.2",
"unplugin-vue-components": "^0.26.0",
+ "unplugin-vue-router": "^0.7.0",
"vite": "^5.0.10",
"vite-plugin-mock-dev-server": "^1.4.3",
"vite-plugin-vconsole": "^2.0.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index cf4826c2..6cbb6775 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -133,6 +133,9 @@ devDependencies:
unplugin-vue-components:
specifier: ^0.26.0
version: 0.26.0(rollup@4.9.1)(vue@3.3.13)
+ unplugin-vue-router:
+ specifier: ^0.7.0
+ version: 0.7.0(rollup@4.9.1)(vue-router@4.2.5)(vue@3.3.13)
vite:
specifier: ^5.0.10
version: 5.0.10(@types/node@20.10.5)(less@4.2.0)(terser@5.26.0)
@@ -2660,6 +2663,26 @@ packages:
path-browserify: 1.0.1
dev: true
+ /@vue-macros/common@1.10.0(rollup@4.9.1)(vue@3.3.13):
+ resolution: {integrity: sha512-4DZsPeQA/nBQDw2RkYAmH7KrFjJVrMdAhJhO1JCl1bbbFXCGeoGjXfkg9wHPppj47s2HpAB3GrqNwqVGbi12NQ==}
+ engines: {node: '>=16.14.0'}
+ peerDependencies:
+ vue: ^2.7.0 || ^3.2.25
+ peerDependenciesMeta:
+ vue:
+ optional: true
+ dependencies:
+ '@babel/types': 7.23.6
+ '@rollup/pluginutils': 5.1.0(rollup@4.9.1)
+ '@vue/compiler-sfc': 3.3.13
+ ast-kit: 0.11.3(rollup@4.9.1)
+ local-pkg: 0.5.0
+ magic-string-ast: 0.3.0
+ vue: 3.3.13(typescript@5.3.3)
+ transitivePeerDependencies:
+ - rollup
+ dev: true
+
/@vue/babel-helper-vue-transform-on@1.1.5:
resolution: {integrity: sha512-SgUymFpMoAyWeYWLAY+MkCK3QEROsiUnfaw5zxOVD/M64KQs8D/4oK6Q5omVA2hnvEOE0SCkH2TZxs/jnnUj7w==}
dev: true
@@ -2719,7 +2742,6 @@ packages:
/@vue/devtools-api@6.5.1:
resolution: {integrity: sha512-+KpckaAQyfbvshdDW5xQylLni1asvNSGme1JFs8I1+/H5pHEhqUKMEQD/qn3Nx5+/nycBq11qAEi8lk+LXI2dA==}
- dev: false
/@vue/language-core@1.8.25(typescript@5.3.3):
resolution: {integrity: sha512-NJk/5DnAZlpvXX8BdWmHI45bWGLViUaS3R/RMrmFSvFMSbJKuEODpM4kR0F0Ofv5SFzCWuNiMhxameWpVdQsnA==}
@@ -2895,6 +2917,38 @@ packages:
resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==}
dev: true
+ /ast-kit@0.11.3(rollup@4.9.1):
+ resolution: {integrity: sha512-qdwwKEhckRk0XE22/xDdmU3v/60E8Edu4qFhgTLIhGGDs/PAJwLw9pQn8Rj99PitlbBZbYpx0k/lbir4kg0SuA==}
+ engines: {node: '>=16.14.0'}
+ dependencies:
+ '@babel/parser': 7.23.6
+ '@rollup/pluginutils': 5.1.0(rollup@4.9.1)
+ pathe: 1.1.1
+ transitivePeerDependencies:
+ - rollup
+ dev: true
+
+ /ast-kit@0.9.5(rollup@4.9.1):
+ resolution: {integrity: sha512-kbL7ERlqjXubdDd+szuwdlQ1xUxEz9mCz1+m07ftNVStgwRb2RWw+U6oKo08PAvOishMxiqz1mlJyLl8yQx2Qg==}
+ engines: {node: '>=16.14.0'}
+ dependencies:
+ '@babel/parser': 7.23.6
+ '@rollup/pluginutils': 5.1.0(rollup@4.9.1)
+ pathe: 1.1.1
+ transitivePeerDependencies:
+ - rollup
+ dev: true
+
+ /ast-walker-scope@0.5.0(rollup@4.9.1):
+ resolution: {integrity: sha512-NsyHMxBh4dmdEHjBo1/TBZvCKxffmZxRYhmclfu0PP6Aftre47jOHYaYaNqJcV0bxihxFXhDkzLHUwHc0ocd0Q==}
+ engines: {node: '>=16.14.0'}
+ dependencies:
+ '@babel/parser': 7.23.6
+ ast-kit: 0.9.5(rollup@4.9.1)
+ transitivePeerDependencies:
+ - rollup
+ dev: true
+
/asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
dev: false
@@ -5173,6 +5227,13 @@ packages:
yallist: 4.0.0
dev: true
+ /magic-string-ast@0.3.0:
+ resolution: {integrity: sha512-0shqecEPgdFpnI3AP90epXyxZy9g6CRZ+SZ7BcqFwYmtFEnZ1jpevcV5HoyVnlDS9gCnc1UIg3Rsvp3Ci7r8OA==}
+ engines: {node: '>=16.14.0'}
+ dependencies:
+ magic-string: 0.30.5
+ dev: true
+
/magic-string@0.30.5:
resolution: {integrity: sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==}
engines: {node: '>=12'}
@@ -6717,6 +6778,33 @@ packages:
- supports-color
dev: true
+ /unplugin-vue-router@0.7.0(rollup@4.9.1)(vue-router@4.2.5)(vue@3.3.13):
+ resolution: {integrity: sha512-ddRreGq0t5vlSB7OMy4e4cfU1w2AwBQCwmvW3oP/0IHQiokzbx4hd3TpwBu3eIAFVuhX2cwNQwp1U32UybTVCw==}
+ peerDependencies:
+ vue-router: ^4.1.0
+ peerDependenciesMeta:
+ vue-router:
+ optional: true
+ dependencies:
+ '@babel/types': 7.23.6
+ '@rollup/pluginutils': 5.1.0(rollup@4.9.1)
+ '@vue-macros/common': 1.10.0(rollup@4.9.1)(vue@3.3.13)
+ ast-walker-scope: 0.5.0(rollup@4.9.1)
+ chokidar: 3.5.3
+ fast-glob: 3.3.2
+ json5: 2.2.3
+ local-pkg: 0.4.3
+ mlly: 1.4.2
+ pathe: 1.1.1
+ scule: 1.1.1
+ unplugin: 1.5.1
+ vue-router: 4.2.5(vue@3.3.13)
+ yaml: 2.3.4
+ transitivePeerDependencies:
+ - rollup
+ - vue
+ dev: true
+
/unplugin@1.5.1:
resolution: {integrity: sha512-0QkvG13z6RD+1L1FoibQqnvTwVBXvS4XSPwAyinVgoOCl2jAgwzdUKmEj05o4Lt8xwQI85Hb6mSyYkcAGwZPew==}
dependencies:
@@ -6985,7 +7073,6 @@ packages:
dependencies:
'@vue/devtools-api': 6.5.1
vue: 3.3.13(typescript@5.3.3)
- dev: false
/vue-template-compiler@2.7.15:
resolution: {integrity: sha512-yQxjxMptBL7UAog00O8sANud99C6wJF+7kgbcwqkvA38vCGF7HWE66w0ZFnS/kX5gSoJr/PQ4/oS3Ne2pW37Og==}
diff --git a/src/auto-imports.d.ts b/src/auto-imports.d.ts
index 64fe7239..949508db 100644
--- a/src/auto-imports.d.ts
+++ b/src/auto-imports.d.ts
@@ -17,6 +17,8 @@ declare global {
const customRef: typeof import('vue')['customRef']
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 describe: typeof import('vitest')['describe']
const effectScope: typeof import('vue')['effectScope']
const expect: typeof import('vitest')['expect']
@@ -33,8 +35,8 @@ declare global {
const nextTick: typeof import('vue')['nextTick']
const onActivated: typeof import('vue')['onActivated']
const onBeforeMount: typeof import('vue')['onBeforeMount']
- const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave']
- const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate']
+ const onBeforeRouteLeave: typeof import('vue-router/auto')['onBeforeRouteLeave']
+ const onBeforeRouteUpdate: typeof import('vue-router/auto')['onBeforeRouteUpdate']
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
const onDeactivated: typeof import('vue')['onDeactivated']
@@ -65,9 +67,9 @@ declare global {
const useAttrs: typeof import('vue')['useAttrs']
const useCssModule: typeof import('vue')['useCssModule']
const useCssVars: typeof import('vue')['useCssVars']
- const useLink: typeof import('vue-router')['useLink']
- const useRoute: typeof import('vue-router')['useRoute']
- const useRouter: typeof import('vue-router')['useRouter']
+ const useLink: typeof import('vue-router/auto')['useLink']
+ const useRoute: typeof import('vue-router/auto')['useRoute']
+ const useRouter: typeof import('vue-router/auto')['useRouter']
const useSlots: typeof import('vue')['useSlots']
const vi: typeof import('vitest')['vi']
const vitest: typeof import('vitest')['vitest']
diff --git a/src/router/README.md b/src/router/README.md
new file mode 100644
index 00000000..9f54f64c
--- /dev/null
+++ b/src/router/README.md
@@ -0,0 +1,4 @@
+## File-based Routing
+
+Routes will be auto-generated for Vue files in the **src/views** dir with the same file structure.
+Check out [`unplugin-vue-router`](https://github.com/posva/unplugin-vue-router) for more details.
diff --git a/src/router/index.ts b/src/router/index.ts
index cc81010e..75c92797 100644
--- a/src/router/index.ts
+++ b/src/router/index.ts
@@ -1,44 +1,12 @@
// https://router.vuejs.org/zh/
-import { createRouter, createWebHistory } from 'vue-router'
+
+import { createRouter, createWebHistory } from 'vue-router/auto'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
-// 导入路由组件
-import main from '@/views/index.vue'
-import mock from '@/views/mock/index.vue'
-import charts from '@/views/charts/index.vue'
-import unocss from '@/views/unocss/index.vue'
-
NProgress.configure({ showSpinner: true, parent: '#app' })
-
-// 定义路由,每个路由都需要映射到一个组件
-const routes = [
- {
- path: '/',
- name: 'main',
- component: main,
- },
- {
- path: '/mock',
- name: 'mock',
- component: mock,
- },
- {
- path: '/charts',
- name: 'charts',
- component: charts,
- },
- {
- path: '/unocss',
- name: 'unocss',
- component: unocss,
- },
-]
-
-// 创建路由实例并传递 `routes` 配置
const router = createRouter({
history: createWebHistory(import.meta.env.VITE_APP_PUBLIC_PATH),
- routes,
})
router.beforeEach((_to, _from, next) => {
diff --git a/src/typed-router.d.ts b/src/typed-router.d.ts
new file mode 100644
index 00000000..32844fb4
--- /dev/null
+++ b/src/typed-router.d.ts
@@ -0,0 +1,144 @@
+/* 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.
+
+///
+
+import type {
+ // type safe route locations
+ RouteLocationTypedList,
+ RouteLocationResolvedTypedList,
+ RouteLocationNormalizedTypedList,
+ RouteLocationNormalizedLoadedTypedList,
+ RouteLocationAsString,
+ RouteLocationAsRelativeTypedList,
+ RouteLocationAsPathTypedList,
+
+ // helper types
+ // route definitions
+ RouteRecordInfo,
+ ParamValue,
+ ParamValueOneOrMore,
+ ParamValueZeroOrMore,
+ ParamValueZeroOrOne,
+
+ // vue-router extensions
+ _RouterTyped,
+ RouterLinkTyped,
+ RouterLinkPropsTyped,
+ NavigationGuard,
+ UseLinkFnTyped,
+
+ // data fetching
+ _DataLoader,
+ _DefineLoaderOptions,
+} from 'unplugin-vue-router/types'
+
+declare module 'vue-router/auto/routes' {
+ export interface RouteNamedMap {
+ '/': RouteRecordInfo<'/', '/', Record, Record>,
+ '/charts/': RouteRecordInfo<'/charts/', '/charts', Record, Record>,
+ '/mock/': RouteRecordInfo<'/mock/', '/mock', Record, Record>,
+ '/unocss/': RouteRecordInfo<'/unocss/', '/unocss', Record, Record>,
+ }
+}
+
+declare module 'vue-router/auto' {
+ import type { RouteNamedMap } from 'vue-router/auto/routes'
+
+ export type RouterTyped = _RouterTyped
+
+ /**
+ * Type safe version of `RouteLocationNormalized` (the type of `to` and `from` in navigation guards).
+ * Allows passing the name of the route to be passed as a generic.
+ */
+ export type RouteLocationNormalized = RouteLocationNormalizedTypedList[Name]
+
+ /**
+ * Type safe version of `RouteLocationNormalizedLoaded` (the return type of `useRoute()`).
+ * Allows passing the name of the route to be passed as a generic.
+ */
+ export type RouteLocationNormalizedLoaded = RouteLocationNormalizedLoadedTypedList[Name]
+
+ /**
+ * Type safe version of `RouteLocationResolved` (the returned route of `router.resolve()`).
+ * Allows passing the name of the route to be passed as a generic.
+ */
+ export type RouteLocationResolved = RouteLocationResolvedTypedList[Name]
+
+ /**
+ * Type safe version of `RouteLocation` . Allows passing the name of the route to be passed as a generic.
+ */
+ export type RouteLocation = RouteLocationTypedList[Name]
+
+ /**
+ * Type safe version of `RouteLocationRaw` . Allows passing the name of the route to be passed as a generic.
+ */
+ export type RouteLocationRaw =
+ | RouteLocationAsString
+ | RouteLocationAsRelativeTypedList[Name]
+ | RouteLocationAsPathTypedList[Name]
+
+ /**
+ * Generate a type safe params for a route location. Requires the name of the route to be passed as a generic.
+ */
+ export type RouteParams = RouteNamedMap[Name]['params']
+ /**
+ * Generate a type safe raw params for a route location. Requires the name of the route to be passed as a generic.
+ */
+ export type RouteParamsRaw = RouteNamedMap[Name]['paramsRaw']
+
+ export function useRouter(): RouterTyped
+ export function useRoute(name?: Name): RouteLocationNormalizedLoadedTypedList[Name]
+
+ export const useLink: UseLinkFnTyped
+
+ export function onBeforeRouteLeave(guard: NavigationGuard): void
+ export function onBeforeRouteUpdate(guard: NavigationGuard): void
+
+ export const RouterLink: RouterLinkTyped
+ export const RouterLinkProps: RouterLinkPropsTyped
+
+ // Experimental Data Fetching
+
+ export function defineLoader<
+ P extends Promise,
+ Name extends keyof RouteNamedMap = keyof RouteNamedMap,
+ isLazy extends boolean = false,
+ >(
+ name: Name,
+ loader: (route: RouteLocationNormalizedLoaded) => P,
+ options?: _DefineLoaderOptions,
+ ): _DataLoader, isLazy>
+ export function defineLoader<
+ P extends Promise,
+ isLazy extends boolean = false,
+ >(
+ loader: (route: RouteLocationNormalizedLoaded) => P,
+ options?: _DefineLoaderOptions,
+ ): _DataLoader, isLazy>
+
+ export {
+ _definePage as definePage,
+ _HasDataLoaderMeta as HasDataLoaderMeta,
+ _setupDataFetchingGuard as setupDataFetchingGuard,
+ _stopDataFetchingScope as stopDataFetchingScope,
+ } from 'unplugin-vue-router/runtime'
+}
+
+declare module 'vue-router' {
+ import type { RouteNamedMap } from 'vue-router/auto/routes'
+
+ export interface TypesConfig {
+ beforeRouteUpdate: NavigationGuard
+ beforeRouteLeave: NavigationGuard
+
+ $route: RouteLocationNormalizedLoadedTypedList[keyof RouteNamedMap]
+ $router: _RouterTyped
+
+ RouterLink: RouterLinkTyped
+ }
+}
diff --git a/vite.config.ts b/vite.config.ts
index 23d2d088..2807fc0c 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -6,6 +6,8 @@ import type { ConfigEnv, UserConfig } from 'vite'
import { visualizer } from 'rollup-plugin-visualizer'
import Components from 'unplugin-vue-components/vite'
import AutoImport from 'unplugin-auto-import/vite'
+import VueRouter from 'unplugin-vue-router/vite'
+import { VueRouterAutoImports } from 'unplugin-vue-router'
import { VantResolver } from 'unplugin-vue-components/resolvers'
import vue from '@vitejs/plugin-vue'
@@ -28,6 +30,11 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
base: env.VITE_APP_PUBLIC_PATH,
plugins: [
+ VueRouter({
+ routesFolder: 'src/views',
+ dts: 'src/typed-router.d.ts',
+ }),
+
vue(),
vueJsx(),
visualizer(),
@@ -52,8 +59,11 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
/\.vue\?vue/,
],
imports: [
+ VueRouterAutoImports,
+ {
+ 'vue-router/auto': ['useLink'],
+ },
'vue',
- 'vue-router',
'vitest',
],
dts: 'src/auto-imports.d.ts',