Skip to content

Commit 00e7945

Browse files
committed
refactor(core): 引入内部模块与安装覆盖机制,重构安装流程核心实现
1 parent 9dedc60 commit 00e7945

File tree

9 files changed

+159
-88
lines changed

9 files changed

+159
-88
lines changed

src/create-router.ts

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import type { RouterOptions as _RouterOptions, Router } from 'vue-router'
22
import type { RouterPlugin } from './plugin'
33
import { createRouter as _createRouter } from 'vue-router'
4-
import { RUN_WITH_APP_HANDLERS_KEY } from './meta-keys'
5-
import { prepareInstall } from './prepare-install'
4+
import { overrideRouterInstall } from './override-router-install'
65
import { setupPlugin } from './setup-plugin'
76

87
export interface RouterOptions extends _RouterOptions {
@@ -33,17 +32,7 @@ export function createRouter(options: RouterOptions): Router {
3332
const router = _createRouter(options)
3433

3534
// 重写 install 方法
36-
const { install } = router
37-
router.install = (...args) => {
38-
const [app] = args
39-
prepareInstall({ app, router })
40-
install.apply(router, args)
41-
42-
// 运行缓存的 runWithApp 函数
43-
const runWithAppHandlers = (router[RUN_WITH_APP_HANDLERS_KEY] ??= [])
44-
runWithAppHandlers.forEach(handler => handler(app))
45-
runWithAppHandlers.length = 0
46-
}
35+
overrideRouterInstall(router)
4736

4837
// 安装插件
4938
const { plugins = [] } = options

src/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
export * from './as-vue-plugin'
21
export * from './create-router'
3-
export * from './create-vue-router-plugin'
2+
export * from './deprecated/as-vue-plugin'
3+
export * from './deprecated/create-vue-router-plugin'
44
export * from './plugin'
5+
export * from './with-install'

src/internals.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import type { Router } from 'vue-router'
2+
import type { RouterPluginSystemInternals } from './types/vue-router'
3+
import { effectScope } from 'vue'
4+
5+
export const INTERNALS_KEY = '__VUE_ROUTER_PLUGIN_SYSTEM_INTERNALS__' as const
6+
7+
export function getInternals(router: Router): RouterPluginSystemInternals {
8+
if (!router[INTERNALS_KEY]) {
9+
router[INTERNALS_KEY] = {
10+
isInstallOverridden: false,
11+
isPrepared: false,
12+
app: undefined,
13+
effectScope: effectScope(true),
14+
uninstallHandlers: [],
15+
runWithAppHandlers: [],
16+
}
17+
}
18+
return router[INTERNALS_KEY]
19+
}

src/meta-keys.ts

Lines changed: 0 additions & 38 deletions
This file was deleted.

src/override-router-install.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import type { Router } from 'vue-router'
2+
import { getInternals } from './internals'
3+
import { prepareInstall } from './prepare-install'
4+
5+
/**
6+
* 重写路由器的 install 方法
7+
*
8+
* @param router 路由器实例
9+
*/
10+
export function overrideRouterInstall(router: Router): void {
11+
const internals = getInternals(router)
12+
if (internals.isInstallOverridden) {
13+
return
14+
}
15+
16+
// 避免重复重写
17+
internals.isInstallOverridden = true
18+
19+
// 重写 install 方法
20+
const { install } = router
21+
router.install = (...args) => {
22+
const [app] = args
23+
24+
// 准备安装
25+
prepareInstall({ app, router })
26+
// 执行原始 install 方法
27+
install.apply(router, args)
28+
29+
// 运行缓存的 runWithApp 函数
30+
internals.runWithAppHandlers.forEach(handler => handler(app))
31+
internals.runWithAppHandlers.length = 0
32+
}
33+
}

src/prepare-install.ts

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
11
import type { App } from 'vue'
22
import type { Router } from 'vue-router'
3-
import {
4-
APP_KEY,
5-
EFFECT_SCOPE_KEY,
6-
PREPARED_FLAG_KEY,
7-
RUN_WITH_APP_HANDLERS_KEY,
8-
UNINSTALL_HANDLERS_KEY,
9-
} from './meta-keys'
3+
import { getInternals } from './internals'
104

115
/**
126
* 在正式安装到 vue app 前运行此函数,以准备安装
@@ -18,28 +12,24 @@ export function prepareInstall({
1812
app: App
1913
router: Router
2014
}): void {
21-
if (router[PREPARED_FLAG_KEY]) {
15+
const internals = getInternals(router)
16+
if (internals.isPrepared) {
2217
return
2318
}
2419

2520
// 避免重复执行后续操作
26-
router[PREPARED_FLAG_KEY] = true
21+
internals.isPrepared = true
2722

2823
// 用于 setupPlugin 内访问 vue app
29-
router[APP_KEY] = app
24+
internals.app = app
3025

3126
// 注册卸载函数
32-
// TODO: use https://github.com/vuejs/core/pull/8801 if merged
3327
const { unmount } = app
3428
app.unmount = () => {
35-
router[EFFECT_SCOPE_KEY]?.stop()
36-
router[UNINSTALL_HANDLERS_KEY]?.forEach(handler => handler())
37-
38-
delete router[PREPARED_FLAG_KEY]
39-
delete router[APP_KEY]
40-
delete router[EFFECT_SCOPE_KEY]
41-
delete router[UNINSTALL_HANDLERS_KEY]
42-
delete router[RUN_WITH_APP_HANDLERS_KEY]
29+
internals.effectScope.stop()
30+
internals.uninstallHandlers.forEach(handler => handler())
31+
internals.uninstallHandlers.length = 0
32+
internals.runWithAppHandlers.length = 0
4333

4434
return unmount.call(app)
4535
}

src/setup-plugin.ts

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
11
import type { Router } from 'vue-router'
22
import type { RouterPlugin } from './plugin'
3-
import { effectScope } from 'vue'
4-
import {
5-
APP_KEY,
6-
EFFECT_SCOPE_KEY,
7-
RUN_WITH_APP_HANDLERS_KEY,
8-
UNINSTALL_HANDLERS_KEY,
9-
} from './meta-keys'
3+
import { getInternals } from './internals'
104

115
/**
126
* 安装单一插件
@@ -18,28 +12,26 @@ export function setupPlugin({
1812
router: Router
1913
plugin: RouterPlugin
2014
}): void {
21-
const scope = (router[EFFECT_SCOPE_KEY] ??= effectScope(true))
15+
const internals = getInternals(router)
2216
// 在 scope 中运行插件
23-
scope.run(() => {
17+
internals.effectScope.run(() => {
2418
plugin({
2519
router,
2620
onUninstall(handler) {
27-
const handlers = (router[UNINSTALL_HANDLERS_KEY] ??= [])
28-
handlers.push(handler)
21+
internals.uninstallHandlers.push(handler)
2922
},
3023
runWithApp(handler) {
3124
// 在 scope 中运行 handler
3225
const rawHandler = handler
3326
handler = (...args) => {
34-
return scope.run(() => rawHandler(...args))
27+
return internals.effectScope.run(() => rawHandler(...args))
3528
}
3629

37-
if (router[APP_KEY]) {
38-
handler(router[APP_KEY])
30+
if (internals.app) {
31+
handler(internals.app)
3932
}
4033
else {
41-
const handlers = (router[RUN_WITH_APP_HANDLERS_KEY] ??= [])
42-
handlers.push(handler)
34+
internals.runWithAppHandlers.push(handler)
4335
}
4436
},
4537
})

src/types/vue-router.d.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import type { App, EffectScope } from 'vue'
2+
import type { INTERNALS_KEY } from '../internals'
3+
import type {
4+
RouterPluginRunWithAppHandler,
5+
RouterPluginUninstallHandler,
6+
} from '../plugin'
7+
8+
export interface RouterPluginSystemInternals {
9+
isInstallOverridden: boolean
10+
isPrepared: boolean
11+
app: App | undefined
12+
effectScope: EffectScope
13+
uninstallHandlers: RouterPluginUninstallHandler[]
14+
runWithAppHandlers: RouterPluginRunWithAppHandler[]
15+
}
16+
17+
declare module 'vue-router' {
18+
export interface Router {
19+
/**
20+
* Internal data for vue-router-plugin-system.
21+
* @internal
22+
*/
23+
[INTERNALS_KEY]?: RouterPluginSystemInternals
24+
}
25+
}

src/with-install.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import type { App } from 'vue'
2+
import type { Router } from 'vue-router'
3+
import type { RouterPlugin } from './plugin'
4+
import { overrideRouterInstall } from './override-router-install'
5+
import { prepareInstall } from './prepare-install'
6+
import { setupPlugin } from './setup-plugin'
7+
8+
export interface RouterPluginInstall {
9+
/**
10+
* Install the plugin.
11+
* @param instance App or Router instance
12+
*/
13+
install: (instance: App | Router) => void
14+
}
15+
16+
/**
17+
* Add an `install` method to the plugin to adapt it to Vue's plugin registration mechanism,
18+
* or to manually install the plugin with an router instance.
19+
*
20+
* @example
21+
* ```ts
22+
* const SomePlugin = withInstall((ctx) => {
23+
* // plugin implementation
24+
* })
25+
*
26+
* // install with router
27+
* SomePlugin.install(router)
28+
*
29+
* // install with app
30+
* // must be installed after the router
31+
* app.use(router).use(SomePlugin)
32+
* ```
33+
*/
34+
export function withInstall(
35+
plugin: RouterPlugin,
36+
): RouterPlugin & RouterPluginInstall {
37+
return Object.assign(plugin, {
38+
install(instance: App | Router) {
39+
if (isRouter(instance)) {
40+
overrideRouterInstall(instance)
41+
setupPlugin({ router: instance, plugin })
42+
}
43+
else {
44+
const router = instance.config.globalProperties.$router
45+
if (!router) {
46+
throw new Error(
47+
'[vue-router-plugin-system] Please install vue-router first.',
48+
)
49+
}
50+
51+
prepareInstall({ app: instance, router })
52+
setupPlugin({ router, plugin })
53+
}
54+
},
55+
})
56+
}
57+
58+
function isRouter(instance: any): instance is Router {
59+
return !!instance.install && !!instance.options && !!instance.currentRoute
60+
}

0 commit comments

Comments
 (0)