From c78c940150b837293c94a507e81c9e65006e4c69 Mon Sep 17 00:00:00 2001 From: GaoNeng-wWw Date: Mon, 18 Dec 2023 13:39:26 +0800 Subject: [PATCH 1/5] feat(runtime-vapor): onErrorCaptured --- packages/runtime-vapor/src/apiLifecycle.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/runtime-vapor/src/apiLifecycle.ts b/packages/runtime-vapor/src/apiLifecycle.ts index eff675728..6f26cc684 100644 --- a/packages/runtime-vapor/src/apiLifecycle.ts +++ b/packages/runtime-vapor/src/apiLifecycle.ts @@ -1,3 +1,4 @@ +import { ComponentPublicInstance } from '@vue/runtime-core' import { type ComponentInternalInstance, currentInstance } from './component' export enum VaporLifecycleHooks { @@ -46,3 +47,16 @@ export const onBeforeUpdate = createHook(VaporLifecycleHooks.BEFORE_UPDATE) export const onUpdated = createHook(VaporLifecycleHooks.UPDATED) export const onBeforeUnmount = createHook(VaporLifecycleHooks.BEFORE_UNMOUNT) export const onUnmounted = createHook(VaporLifecycleHooks.UNMOUNTED) + +export type ErrorCapturedHook = ( + err: TError, + instance: ComponentPublicInstance | null, + info: string, +) => boolean | void + +export function onErrorCaptured( + hook: ErrorCapturedHook, + target: ComponentInternalInstance | null = currentInstance, +) { + injectHook(VaporLifecycleHooks.ERROR_CAPTURED, hook, target) +} From b2419bf61c309f8b52105321cfc3f284993d12ca Mon Sep 17 00:00:00 2001 From: GaoNeng-wWw Date: Sat, 23 Dec 2023 20:08:45 +0800 Subject: [PATCH 2/5] fix: Solution suggestions --- packages/runtime-vapor/src/apiLifecycle.ts | 45 ++++++++++++++++--- .../src/componentPublicInstance.ts | 22 ++++++++- 2 files changed, 59 insertions(+), 8 deletions(-) diff --git a/packages/runtime-vapor/src/apiLifecycle.ts b/packages/runtime-vapor/src/apiLifecycle.ts index 6f26cc684..f03dbc988 100644 --- a/packages/runtime-vapor/src/apiLifecycle.ts +++ b/packages/runtime-vapor/src/apiLifecycle.ts @@ -1,5 +1,14 @@ -import { ComponentPublicInstance } from '@vue/runtime-core' -import { type ComponentInternalInstance, currentInstance } from './component' +import { ComponentPublicInstance } from './componentPublicInstance' +import { + type ComponentInternalInstance, + currentInstance, + setCurrentInstance, + unsetCurrentInstance, +} from './component' +import { warn } from './warning' +import { pauseTracking, resetTracking } from '@vue/reactivity' +import { ErrorTypeStrings, callWithAsyncErrorHandling } from './errorHandling' +import { toHandlerKey } from '@vue/shared' export enum VaporLifecycleHooks { BEFORE_CREATE = 'bc', @@ -20,20 +29,42 @@ export enum VaporLifecycleHooks { export const injectHook = ( type: VaporLifecycleHooks, - hook: Function, + hook: Function & { __weh?: Function }, target: ComponentInternalInstance | null = currentInstance, prepend: boolean = false, ) => { if (target) { const hooks = target[type] || (target[type] = []) + const wrappedHook = + hook.__weh || + (hook.__weh = (...args: unknown[]) => { + if (target.isUnmounted) { + return + } + pauseTracking() + setCurrentInstance(target) + const res = callWithAsyncErrorHandling(hook, target, type, args) + unsetCurrentInstance() + resetTracking() + return res + }) if (prepend) { - hooks.unshift(hook) + hooks.unshift(wrappedHook) } else { - hooks.push(hook) + hooks.push(wrappedHook) } - return hook + return wrappedHook } else if (__DEV__) { - // TODO: warn need + const apiName = toHandlerKey(ErrorTypeStrings[type].replace(/ hook$/, '')) + warn( + `${apiName} is called when there is no active component instance to be ` + + `associated with. ` + + `Lifecycle injection APIs can only be used during execution of setup().` + + (__FEATURE_SUSPENSE__ + ? ` If you are using async setup(), make sure to register lifecycle ` + + `hooks before the first await statement.` + : ``), + ) } } export const createHook = diff --git a/packages/runtime-vapor/src/componentPublicInstance.ts b/packages/runtime-vapor/src/componentPublicInstance.ts index 8bfacf981..f3d8d7f1e 100644 --- a/packages/runtime-vapor/src/componentPublicInstance.ts +++ b/packages/runtime-vapor/src/componentPublicInstance.ts @@ -1,5 +1,25 @@ -import { hasOwn } from '@vue/shared' +import { Data, IfAny, Prettify, hasOwn } from '@vue/shared' import { type ComponentInternalInstance } from './component' +import { ShallowUnwrapRef, UnwrapNestedRefs } from '@vue/reactivity' +import { WatchOptions, WatchStopHandle } from './apiWatch' +import { nextTick } from '.' + +export type ComponentPublicInstance< + P = {}, // props type extracted from props option + B = {}, // raw bindings returned from setup() + D = {}, // return from data() + // TODO: not ready yet + + // C extends ComputedOptions = {}, + // M extends MethodOptions = {}, + // E extends EmitsOptions = {}, + // PublicProps = P, + // Defaults = {}, + // MakeDefaultsOptional extends boolean = false, + // Options = ComponentOptionsBase, + // I extends ComponentInjectOptions = {}, + // S extends SlotsType = {} +> = {} export interface ComponentRenderContext { [key: string]: any From 1d05cfd638b313320fc2087cde0bd2740a09dffe Mon Sep 17 00:00:00 2001 From: GaoNeng-wWw Date: Sun, 24 Dec 2023 21:11:16 +0800 Subject: [PATCH 3/5] fix(runtime-vapor): TS6133 error --- packages/runtime-vapor/src/componentPublicInstance.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/runtime-vapor/src/componentPublicInstance.ts b/packages/runtime-vapor/src/componentPublicInstance.ts index f3d8d7f1e..10f8e2312 100644 --- a/packages/runtime-vapor/src/componentPublicInstance.ts +++ b/packages/runtime-vapor/src/componentPublicInstance.ts @@ -1,8 +1,5 @@ -import { Data, IfAny, Prettify, hasOwn } from '@vue/shared' +import { hasOwn } from '@vue/shared' import { type ComponentInternalInstance } from './component' -import { ShallowUnwrapRef, UnwrapNestedRefs } from '@vue/reactivity' -import { WatchOptions, WatchStopHandle } from './apiWatch' -import { nextTick } from '.' export type ComponentPublicInstance< P = {}, // props type extracted from props option From e3f4a78c901529ec6d009b6470271c89e1097c1d Mon Sep 17 00:00:00 2001 From: GaoNeng-wWw Date: Sun, 24 Dec 2023 21:36:54 +0800 Subject: [PATCH 4/5] fix(runtime-vapor): unit test error --- packages/runtime-vapor/src/apiLifecycle.ts | 18 +----------------- packages/runtime-vapor/src/component.ts | 2 +- packages/runtime-vapor/src/enums.ts | 16 ++++++++++++++++ packages/runtime-vapor/src/errorHandling.ts | 2 +- 4 files changed, 19 insertions(+), 19 deletions(-) create mode 100644 packages/runtime-vapor/src/enums.ts diff --git a/packages/runtime-vapor/src/apiLifecycle.ts b/packages/runtime-vapor/src/apiLifecycle.ts index f03dbc988..864d90609 100644 --- a/packages/runtime-vapor/src/apiLifecycle.ts +++ b/packages/runtime-vapor/src/apiLifecycle.ts @@ -9,23 +9,7 @@ import { warn } from './warning' import { pauseTracking, resetTracking } from '@vue/reactivity' import { ErrorTypeStrings, callWithAsyncErrorHandling } from './errorHandling' import { toHandlerKey } from '@vue/shared' - -export enum VaporLifecycleHooks { - BEFORE_CREATE = 'bc', - CREATED = 'c', - BEFORE_MOUNT = 'bm', - MOUNTED = 'm', - BEFORE_UPDATE = 'bu', - UPDATED = 'u', - BEFORE_UNMOUNT = 'bum', - UNMOUNTED = 'um', - DEACTIVATED = 'da', - ACTIVATED = 'a', - RENDER_TRIGGERED = 'rtg', - RENDER_TRACKED = 'rtc', - ERROR_CAPTURED = 'ec', - // SERVER_PREFETCH = 'sp', -} +import { VaporLifecycleHooks } from './enums' export const injectHook = ( type: VaporLifecycleHooks, diff --git a/packages/runtime-vapor/src/component.ts b/packages/runtime-vapor/src/component.ts index 63e1f2528..914f7beb6 100644 --- a/packages/runtime-vapor/src/component.ts +++ b/packages/runtime-vapor/src/component.ts @@ -10,7 +10,7 @@ import { } from './componentProps' import type { Data } from '@vue/shared' -import { VaporLifecycleHooks } from './apiLifecycle' +import { VaporLifecycleHooks } from './enums' export type Component = FunctionalComponent | ObjectComponent diff --git a/packages/runtime-vapor/src/enums.ts b/packages/runtime-vapor/src/enums.ts new file mode 100644 index 000000000..b6714f795 --- /dev/null +++ b/packages/runtime-vapor/src/enums.ts @@ -0,0 +1,16 @@ +export enum VaporLifecycleHooks { + BEFORE_CREATE = 'bc', + CREATED = 'c', + BEFORE_MOUNT = 'bm', + MOUNTED = 'm', + BEFORE_UPDATE = 'bu', + UPDATED = 'u', + BEFORE_UNMOUNT = 'bum', + UNMOUNTED = 'um', + DEACTIVATED = 'da', + ACTIVATED = 'a', + RENDER_TRIGGERED = 'rtg', + RENDER_TRACKED = 'rtc', + ERROR_CAPTURED = 'ec', + // SERVER_PREFETCH = 'sp', +} diff --git a/packages/runtime-vapor/src/errorHandling.ts b/packages/runtime-vapor/src/errorHandling.ts index 7c0056512..d7449f3b4 100644 --- a/packages/runtime-vapor/src/errorHandling.ts +++ b/packages/runtime-vapor/src/errorHandling.ts @@ -3,10 +3,10 @@ // The ultimate aim is to uncouple this replicated code and // facilitate its shared use between two runtimes. -import { VaporLifecycleHooks } from './apiLifecycle' import { type ComponentInternalInstance } from './component' import { isFunction, isPromise } from '@vue/shared' import { warn } from './warning' +import { VaporLifecycleHooks } from './enums' // contexts where user provided function may be executed, in addition to // lifecycle hooks. From 34bee69a174a20e139c64a940470424134f85752 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E6=99=BA=E5=AD=90=20Kevin=20Deng?= Date: Mon, 25 Dec 2023 02:42:15 +0800 Subject: [PATCH 5/5] refactor: remove public instance --- packages/runtime-vapor/src/apiLifecycle.ts | 3 +-- .../src/componentPublicInstance.ts | 17 ----------------- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/packages/runtime-vapor/src/apiLifecycle.ts b/packages/runtime-vapor/src/apiLifecycle.ts index 864d90609..5c270d1ca 100644 --- a/packages/runtime-vapor/src/apiLifecycle.ts +++ b/packages/runtime-vapor/src/apiLifecycle.ts @@ -1,4 +1,3 @@ -import { ComponentPublicInstance } from './componentPublicInstance' import { type ComponentInternalInstance, currentInstance, @@ -65,7 +64,7 @@ export const onUnmounted = createHook(VaporLifecycleHooks.UNMOUNTED) export type ErrorCapturedHook = ( err: TError, - instance: ComponentPublicInstance | null, + instance: ComponentInternalInstance | null, info: string, ) => boolean | void diff --git a/packages/runtime-vapor/src/componentPublicInstance.ts b/packages/runtime-vapor/src/componentPublicInstance.ts index 10f8e2312..8bfacf981 100644 --- a/packages/runtime-vapor/src/componentPublicInstance.ts +++ b/packages/runtime-vapor/src/componentPublicInstance.ts @@ -1,23 +1,6 @@ import { hasOwn } from '@vue/shared' import { type ComponentInternalInstance } from './component' -export type ComponentPublicInstance< - P = {}, // props type extracted from props option - B = {}, // raw bindings returned from setup() - D = {}, // return from data() - // TODO: not ready yet - - // C extends ComputedOptions = {}, - // M extends MethodOptions = {}, - // E extends EmitsOptions = {}, - // PublicProps = P, - // Defaults = {}, - // MakeDefaultsOptional extends boolean = false, - // Options = ComponentOptionsBase, - // I extends ComponentInjectOptions = {}, - // S extends SlotsType = {} -> = {} - export interface ComponentRenderContext { [key: string]: any _: ComponentInternalInstance