Skip to content

Commit 27f1137

Browse files
committed
feat: 添加 Vue Router 插件系统支持
- 实现了 RouterPlugin 和 RouterPluginContext 接口 - 添加了 createRouter 函数,支持插件安装 - 实现了插件安装、卸载机制 - 添加了相关单元测试
1 parent c22a861 commit 27f1137

File tree

8 files changed

+352
-46
lines changed

8 files changed

+352
-46
lines changed

package.json

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"bugs": {
1515
"url": "https://github.com/vue-spark/vue-router-plugin-system/issues"
1616
},
17-
"keywords": [],
17+
"keywords": ["vue", "vue-router", "plugin"],
1818
"exports": {
1919
".": "./dist/index.js",
2020
"./package.json": "./package.json"
@@ -40,6 +40,10 @@
4040
"release": "bumpp && pnpm publish",
4141
"prepublishOnly": "pnpm run build"
4242
},
43+
"peerDependencies": {
44+
"vue": "^3.0.0",
45+
"vue-router": "^4.0.0"
46+
},
4347
"devDependencies": {
4448
"@antfu/eslint-config": "^4.16.2",
4549
"@sxzz/prettier-config": "^2.2.3",
@@ -56,7 +60,9 @@
5660
"tsdown": "^0.12.9",
5761
"tsx": "^4.20.3",
5862
"typescript": "^5.8.3",
59-
"vitest": "^3.2.4"
63+
"vitest": "^3.2.4",
64+
"vue": "^3.5.17",
65+
"vue-router": "^4.5.1"
6066
},
6167
"simple-git-hooks": {
6268
"pre-commit": "npx lint-staged"

pnpm-lock.yaml

Lines changed: 112 additions & 31 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/index.ts

Lines changed: 83 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,84 @@
1-
export function myFunction(): string {
2-
return 'Hello, world!'
1+
import type { App } from 'vue'
2+
import type { RouterOptions as _RouterOptions, Router } from 'vue-router'
3+
import type { RouterPlugin, RouterPluginContext } from './plugin'
4+
import { effectScope } from 'vue'
5+
import { createRouter as _createRouter } from 'vue-router'
6+
import { APP_KEY } from './meta-keys'
7+
8+
export interface RouterOptions extends _RouterOptions {
9+
/**
10+
* Plugins to be installed on the router.
11+
*/
12+
plugins?: RouterPlugin[]
13+
}
14+
15+
/**
16+
* Equivalent to {@link createRouter} from `vue-router`, but with support for plugins.
17+
* @param options {@link RouterOptions}
18+
*
19+
* @example
20+
* ```ts
21+
* createRouter({
22+
* history: createWebHistory(),
23+
* routes: [],
24+
* plugins: [SomePlugin()],
25+
* })
26+
* ```
27+
*/
28+
export function createRouter(options: RouterOptions): Router {
29+
const router = _createRouter(options)
30+
const { plugins = [] } = options
31+
32+
const effect = effectScope(true)
33+
const runWithAppFns: ((app: App) => void)[] = []
34+
const uninstallFns: (() => void)[] = []
35+
36+
const ctx: RouterPluginContext = {
37+
router,
38+
39+
runWithApp(fn) {
40+
// 将 fn 包装到 effect 中
41+
const rawFn = fn
42+
fn = function (this: any, ...args) {
43+
return effect.run(() => rawFn.apply(this, args))
44+
}
45+
46+
if (router[APP_KEY]) {
47+
fn(router[APP_KEY])
48+
} else {
49+
runWithAppFns.push(fn)
50+
}
51+
},
52+
53+
onUninstall(fn) {
54+
uninstallFns.push(fn)
55+
},
56+
}
57+
58+
// 在 effect 中执行插件
59+
effect.run(() => {
60+
plugins.forEach((plugin) => plugin(ctx))
61+
})
62+
63+
// 重写 install 方法
64+
const originalInstall = router.install
65+
router.install = (app: App) => {
66+
originalInstall(app)
67+
68+
router[APP_KEY] = app
69+
runWithAppFns.forEach((fn) => fn(app))
70+
runWithAppFns.length = 0
71+
72+
// TODO: use https://github.com/vuejs/core/pull/8801 if merged
73+
const { unmount } = app
74+
app.unmount = () => {
75+
effect.stop()
76+
delete router[APP_KEY]
77+
uninstallFns.forEach((fn) => fn())
78+
uninstallFns.length = 0
79+
unmount.call(app)
80+
}
81+
}
82+
83+
return router
384
}

src/meta-keys.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import type { App } from 'vue'
2+
3+
export const APP_KEY = Symbol('vue app')
4+
5+
declare module 'vue-router' {
6+
export interface Router {
7+
/**
8+
* The vue app instance.
9+
*/
10+
[APP_KEY]?: App
11+
}
12+
}

0 commit comments

Comments
 (0)