Skip to content

Commit 6ba9d40

Browse files
committed
feat(plugin): 插件上下文增加 runWithAppContext 函数来替代 runWithApp
1 parent 0028e64 commit 6ba9d40

File tree

3 files changed

+486
-6
lines changed

3 files changed

+486
-6
lines changed

src/plugin.ts

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,82 @@ import type { App } from 'vue'
22
import type { Router } from 'vue-router'
33

44
export type RouterPluginUninstallHandler = () => void
5+
/**
6+
* @deprecated
7+
* Please use {@link RouterPluginRunWithAppContextHandler} instead.
8+
*/
59
export type RouterPluginRunWithAppHandler = (app: App) => void
10+
export type RouterPluginRunWithAppContextHandler = (app: App) => void
611

712
export interface RouterPluginContext {
813
/**
914
* The router instance.
1015
*/
1116
router: Router
1217
/**
13-
* Runs a function with the vue app.
18+
* @deprecated
19+
* Please use {@link runWithAppContext} instead.
1420
*/
1521
runWithApp: (handler: RouterPluginRunWithAppHandler) => void
22+
/**
23+
* Execute a handler function with access to the Vue App instance and its context.
24+
*
25+
* This method provides a way to access the Vue App instance when the plugin needs to:
26+
* - Use dependency injection (`inject`/`provide`)
27+
* - Access global properties or configurations
28+
* - Create reactive effects that should be automatically cleaned up
29+
*
30+
* **Execution Timing:**
31+
* - If the router is already installed to an app, the handler executes immediately
32+
* - If the router is not yet installed, the handler is queued and will execute when `app.use(router)` is called
33+
*
34+
* **Context and Lifecycle:**
35+
* - The handler runs within the plugin's shared `effectScope`, ensuring automatic cleanup
36+
* - The handler runs within the Vue app's context, enabling `inject()` and other context-dependent APIs
37+
* - Any reactive effects (`watch`, `computed`, etc.) created within the handler are automatically stopped when the plugin is uninstalled
38+
*
39+
* @param handler - Function that receives the Vue App instance and runs within its context
40+
*
41+
* @example
42+
* ```ts
43+
* const Plugin = (ctx) => {
44+
* ctx.runWithAppContext((app) => {
45+
* // ✅ Can use inject() here - runs in app context
46+
* const injected = inject(SomeSymbol)
47+
*
48+
* // ✅ Can access global properties
49+
* const globalConfig = app.config.globalProperties
50+
*
51+
* // ✅ Can use watch() - automatically cleaned up on plugin uninstall
52+
* watch(injected, (newValue) => {
53+
* console.log('Injected value changed:', newValue)
54+
* })
55+
*
56+
* // ✅ Can provide values to child components
57+
* app.provide('pluginData', someData)
58+
* })
59+
* }
60+
* ```
61+
*
62+
* @example
63+
* ```ts
64+
* // Example: Plugin that provides route-based theme
65+
* const ThemePlugin = (ctx) => {
66+
* ctx.runWithAppContext((app) => {
67+
* const theme = ref('light')
68+
*
69+
* // Provide theme to all components
70+
* app.provide('theme', theme)
71+
*
72+
* // Watch route changes and update theme
73+
* watch(ctx.router.currentRoute, (route) => {
74+
* theme.value = route.meta.theme || 'light'
75+
* })
76+
* })
77+
* }
78+
* ```
79+
*/
80+
runWithAppContext: (handler: RouterPluginRunWithAppContextHandler) => void
1681
/**
1782
* Register a function to be called when the plugin is uninstalled.
1883
*/

src/setup-plugin.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { Router } from 'vue-router'
2-
import type { RouterPlugin } from './plugin'
2+
import type { RouterPlugin, RouterPluginContext } from './plugin'
33
import { getInternals } from './internals'
44

55
/**
@@ -15,16 +15,23 @@ export function setupPlugin({
1515
const internals = getInternals(router)
1616
// 在 scope 中运行插件
1717
internals.effectScope.run(() => {
18-
plugin({
18+
const ctx: RouterPluginContext = {
1919
router,
2020
onUninstall(handler) {
2121
internals.uninstallHandlers.push(handler)
2222
},
2323
runWithApp(handler) {
24+
ctx.runWithAppContext(handler)
25+
},
26+
runWithAppContext(handler) {
2427
// 在 scope 中运行 handler
2528
const rawHandler = handler
2629
handler = (...args) => {
27-
return internals.effectScope.run(() => rawHandler(...args))
30+
const [app] = args
31+
return internals.effectScope.run(() =>
32+
// 在 app context 中运行 handler
33+
app.runWithContext(() => rawHandler(...args)),
34+
)
2835
}
2936

3037
if (internals.app) {
@@ -34,6 +41,8 @@ export function setupPlugin({
3441
internals.runWithAppHandlers.push(handler)
3542
}
3643
},
37-
})
44+
}
45+
46+
plugin(ctx)
3847
})
3948
}

0 commit comments

Comments
 (0)