Skip to content

Commit 55c3c8d

Browse files
committed
feat(runtime-core): Plugins can return cleanup function
which is ran at unmount
1 parent bdb1a79 commit 55c3c8d

File tree

2 files changed

+43
-2
lines changed

2 files changed

+43
-2
lines changed

packages/runtime-core/__tests__/apiCreateApp.spec.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,37 @@ describe('api: createApp', () => {
313313
).toHaveBeenWarnedTimes(1)
314314
})
315315

316+
test('use: call cleanup plugin on unmount', () => {
317+
const cleanup = jest.fn().mockName('plugin cleanup')
318+
const PluginA: Plugin = app => {
319+
app.provide('foo', 1)
320+
return cleanup
321+
}
322+
const PluginB: Plugin = {
323+
install: (app, arg1, arg2) => {
324+
app.provide('bar', arg1 + arg2)
325+
return cleanup
326+
}
327+
}
328+
329+
// should ignore non-function return values
330+
const PluginC: Plugin = app => ({})
331+
332+
const app = createApp({
333+
render: () => `Test`
334+
})
335+
app.use(PluginA)
336+
app.use(PluginB)
337+
app.use(PluginC)
338+
339+
const root = nodeOps.createElement('div')
340+
app.mount(root)
341+
342+
app.unmount()
343+
344+
expect(cleanup).toHaveBeenCalledTimes(2)
345+
})
346+
316347
test('config.errorHandler', () => {
317348
const error = new Error()
318349
const count = ref(0)

packages/runtime-core/src/apiCreateApp.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ export function createAppAPI<HostElement>(
185185

186186
const context = createAppContext()
187187
const installedPlugins = new Set()
188+
const pluginCleanupFns: Array<() => any> = []
188189

189190
let isMounted = false
190191

@@ -211,20 +212,28 @@ export function createAppAPI<HostElement>(
211212
},
212213

213214
use(plugin: Plugin, ...options: any[]) {
215+
let cleanupFn: (() => any) | undefined = undefined
214216
if (installedPlugins.has(plugin)) {
215217
__DEV__ && warn(`Plugin has already been applied to target app.`)
216218
} else if (plugin && isFunction(plugin.install)) {
217219
installedPlugins.add(plugin)
218-
plugin.install(app, ...options)
220+
cleanupFn = plugin.install(app, ...options)
219221
} else if (isFunction(plugin)) {
220222
installedPlugins.add(plugin)
221-
plugin(app, ...options)
223+
cleanupFn = plugin(app, ...options)
222224
} else if (__DEV__) {
223225
warn(
224226
`A plugin must either be a function or an object with an "install" ` +
225227
`function.`
226228
)
227229
}
230+
if (
231+
cleanupFn &&
232+
typeof cleanupFn === 'function' &&
233+
cleanupFn.length === 0
234+
) {
235+
pluginCleanupFns.push(cleanupFn)
236+
}
228237
return app
229238
},
230239

@@ -323,6 +332,7 @@ export function createAppAPI<HostElement>(
323332
unmount() {
324333
if (isMounted) {
325334
render(null, app._container)
335+
pluginCleanupFns.map(fn => fn())
326336
if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
327337
app._instance = null
328338
devtoolsUnmountApp(app)

0 commit comments

Comments
 (0)