From e5b79510fb4437475ee30af1e18d204281aab3f1 Mon Sep 17 00:00:00 2001 From: Alex Liu Date: Tue, 18 Jul 2023 00:36:55 +0800 Subject: [PATCH 1/6] feat(app): support app level effect scope --- packages/runtime-dom/src/index.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/runtime-dom/src/index.ts b/packages/runtime-dom/src/index.ts index ad818a34bb7..b6947439dea 100644 --- a/packages/runtime-dom/src/index.ts +++ b/packages/runtime-dom/src/index.ts @@ -10,7 +10,8 @@ import { RootHydrateFunction, isRuntimeOnly, DeprecationTypes, - compatUtils + compatUtils, + effectScope } from '@vue/runtime-core' import { nodeOps } from './nodeOps' import { patchProp } from './patchProp' @@ -63,6 +64,8 @@ export const hydrate = ((...args) => { }) as RootHydrateFunction export const createApp = ((...args) => { + const scope = effectScope() + const app = ensureRenderer().createApp(...args) if (__DEV__) { @@ -70,7 +73,7 @@ export const createApp = ((...args) => { injectCompilerOptionsCheck(app) } - const { mount } = app + const { mount, unmount, runWithContext } = app app.mount = (containerOrSelector: Element | ShadowRoot | string): any => { const container = normalizeContainer(containerOrSelector) if (!container) return @@ -107,6 +110,15 @@ export const createApp = ((...args) => { return proxy } + app.runWithContext = (fn: () => T): T => { + return scope.run(() => runWithContext(fn)) as T + } + + app.unmount = () => { + scope.stop() + unmount() + } + return app }) as CreateAppFunction From 96a3b3233fa322503a5d8c6c9bafbb68bdd9e4a6 Mon Sep 17 00:00:00 2001 From: Alex Liu Date: Wed, 9 Aug 2023 23:48:59 +0800 Subject: [PATCH 2/6] Update packages/runtime-dom/src/index.ts Co-authored-by: Eduardo San Martin Morote --- packages/runtime-dom/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime-dom/src/index.ts b/packages/runtime-dom/src/index.ts index b6947439dea..c86cb133586 100644 --- a/packages/runtime-dom/src/index.ts +++ b/packages/runtime-dom/src/index.ts @@ -64,7 +64,7 @@ export const hydrate = ((...args) => { }) as RootHydrateFunction export const createApp = ((...args) => { - const scope = effectScope() + const scope = effectScope(true) const app = ensureRenderer().createApp(...args) From d2a5fb395e8580eae120eb02bfbbb5a4529daa1f Mon Sep 17 00:00:00 2001 From: Alex Liu Date: Thu, 10 Aug 2023 01:41:46 +0800 Subject: [PATCH 3/6] refactor(app): implement in `runtime-core` instead of `runtime-dom` --- packages/runtime-core/src/apiCreateApp.ts | 5 ++++- packages/runtime-dom/src/index.ts | 16 ++-------------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/packages/runtime-core/src/apiCreateApp.ts b/packages/runtime-core/src/apiCreateApp.ts index c5ac9d68a52..019971e0709 100644 --- a/packages/runtime-core/src/apiCreateApp.ts +++ b/packages/runtime-core/src/apiCreateApp.ts @@ -1,3 +1,4 @@ +import { effectScope } from '@vue/reactivity' import { ConcreteComponent, Data, @@ -210,6 +211,7 @@ export function createAppAPI( rootProps = null } + const scope = effectScope(true) const context = createAppContext() // TODO remove in 3.4 @@ -370,6 +372,7 @@ export function createAppAPI( unmount() { if (isMounted) { + scope.stop() render(null, app._container) if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) { app._instance = null @@ -397,7 +400,7 @@ export function createAppAPI( runWithContext(fn) { currentApp = app try { - return fn() + return scope.run(fn) as ReturnType } finally { currentApp = null } diff --git a/packages/runtime-dom/src/index.ts b/packages/runtime-dom/src/index.ts index c86cb133586..ad818a34bb7 100644 --- a/packages/runtime-dom/src/index.ts +++ b/packages/runtime-dom/src/index.ts @@ -10,8 +10,7 @@ import { RootHydrateFunction, isRuntimeOnly, DeprecationTypes, - compatUtils, - effectScope + compatUtils } from '@vue/runtime-core' import { nodeOps } from './nodeOps' import { patchProp } from './patchProp' @@ -64,8 +63,6 @@ export const hydrate = ((...args) => { }) as RootHydrateFunction export const createApp = ((...args) => { - const scope = effectScope(true) - const app = ensureRenderer().createApp(...args) if (__DEV__) { @@ -73,7 +70,7 @@ export const createApp = ((...args) => { injectCompilerOptionsCheck(app) } - const { mount, unmount, runWithContext } = app + const { mount } = app app.mount = (containerOrSelector: Element | ShadowRoot | string): any => { const container = normalizeContainer(containerOrSelector) if (!container) return @@ -110,15 +107,6 @@ export const createApp = ((...args) => { return proxy } - app.runWithContext = (fn: () => T): T => { - return scope.run(() => runWithContext(fn)) as T - } - - app.unmount = () => { - scope.stop() - unmount() - } - return app }) as CreateAppFunction From 26fbb03c5170f44e85bb4f3a863e5fbf92b4b672 Mon Sep 17 00:00:00 2001 From: Alex Liu Date: Thu, 10 Aug 2023 01:42:45 +0800 Subject: [PATCH 4/6] test: test for app-level effect scope --- .../__tests__/apiCreateApp.spec.ts | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/packages/runtime-core/__tests__/apiCreateApp.spec.ts b/packages/runtime-core/__tests__/apiCreateApp.spec.ts index 637167931d2..70755fa8446 100644 --- a/packages/runtime-core/__tests__/apiCreateApp.spec.ts +++ b/packages/runtime-core/__tests__/apiCreateApp.spec.ts @@ -11,7 +11,8 @@ import { Plugin, ref, getCurrentInstance, - defineComponent + defineComponent, + onScopeDispose } from '@vue/runtime-test' describe('api: createApp', () => { @@ -551,6 +552,26 @@ describe('api: createApp', () => { ).not.toHaveBeenWarned() }) + test('should invoke onScopeDispose when the app unmount', () => { + const spy = vi.fn(() => {}) + const root = nodeOps.createElement('div') + + const app = createApp({ + setup() { + return () => h('div') + } + }) + + app.runWithContext(() => { + onScopeDispose(spy) + }) + + app.mount(root) + app.unmount() + + expect(spy).toHaveBeenCalledTimes(1) + }) + // config.compilerOptions is tested in packages/vue since it is only // supported in the full build. }) From 6ed7c418980411b07956d24b4a3d31be776df0c1 Mon Sep 17 00:00:00 2001 From: Alex Liu Date: Thu, 10 Aug 2023 21:10:12 +0800 Subject: [PATCH 5/6] Update packages/runtime-core/src/apiCreateApp.ts Co-authored-by: Eduardo San Martin Morote --- packages/runtime-core/src/apiCreateApp.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime-core/src/apiCreateApp.ts b/packages/runtime-core/src/apiCreateApp.ts index 019971e0709..9d696bbbeba 100644 --- a/packages/runtime-core/src/apiCreateApp.ts +++ b/packages/runtime-core/src/apiCreateApp.ts @@ -400,7 +400,7 @@ export function createAppAPI( runWithContext(fn) { currentApp = app try { - return scope.run(fn) as ReturnType + return scope.run(fn)! } finally { currentApp = null } From a7141d44e416c9cdccbd60c8ad01cb64620faf49 Mon Sep 17 00:00:00 2001 From: Alex Liu Date: Mon, 24 Jun 2024 19:22:21 +0800 Subject: [PATCH 6/6] feat: adding an effectScope to app instance --- packages/runtime-core/src/apiCreateApp.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/runtime-core/src/apiCreateApp.ts b/packages/runtime-core/src/apiCreateApp.ts index 0b6d4c5ed38..de6e6b7b277 100644 --- a/packages/runtime-core/src/apiCreateApp.ts +++ b/packages/runtime-core/src/apiCreateApp.ts @@ -29,6 +29,7 @@ import { installAppCompatProperties } from './compat/global' import type { NormalizedPropsOptions } from './componentProps' import type { ObjectEmitsOptions } from './componentEmits' import type { DefineComponent } from './apiDefineComponent' +import type { EffectScope } from '@vue/reactivity' export interface App { version: string @@ -71,6 +72,7 @@ export interface App { _container: HostElement | null _context: AppContext _instance: ComponentInternalInstance | null + _scope: EffectScope /** * v2 compat only @@ -229,6 +231,7 @@ export function createAppAPI( _container: null, _context: context, _instance: null, + _scope: scope, version, @@ -402,7 +405,7 @@ export function createAppAPI( const lastApp = currentApp currentApp = app try { - return scope.run(fn)! + return app._scope.run(fn)! } finally { currentApp = lastApp }