Skip to content
This repository was archived by the owner on Jul 19, 2025. It is now read-only.

Commit 3d4bc01

Browse files
GaoNeng-wWwsxzz
andauthored
feat(runtime-vapor): onErrorCaptured (#71)
Co-authored-by: 三咲智子 Kevin Deng <[email protected]>
1 parent d3a86cf commit 3d4bc01

File tree

4 files changed

+69
-25
lines changed

4 files changed

+69
-25
lines changed
Lines changed: 51 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,53 @@
1-
import { type ComponentInternalInstance, currentInstance } from './component'
2-
3-
export enum VaporLifecycleHooks {
4-
BEFORE_CREATE = 'bc',
5-
CREATED = 'c',
6-
BEFORE_MOUNT = 'bm',
7-
MOUNTED = 'm',
8-
BEFORE_UPDATE = 'bu',
9-
UPDATED = 'u',
10-
BEFORE_UNMOUNT = 'bum',
11-
UNMOUNTED = 'um',
12-
DEACTIVATED = 'da',
13-
ACTIVATED = 'a',
14-
RENDER_TRIGGERED = 'rtg',
15-
RENDER_TRACKED = 'rtc',
16-
ERROR_CAPTURED = 'ec',
17-
// SERVER_PREFETCH = 'sp',
18-
}
1+
import {
2+
type ComponentInternalInstance,
3+
currentInstance,
4+
setCurrentInstance,
5+
unsetCurrentInstance,
6+
} from './component'
7+
import { warn } from './warning'
8+
import { pauseTracking, resetTracking } from '@vue/reactivity'
9+
import { ErrorTypeStrings, callWithAsyncErrorHandling } from './errorHandling'
10+
import { toHandlerKey } from '@vue/shared'
11+
import { VaporLifecycleHooks } from './enums'
1912

2013
export const injectHook = (
2114
type: VaporLifecycleHooks,
22-
hook: Function,
15+
hook: Function & { __weh?: Function },
2316
target: ComponentInternalInstance | null = currentInstance,
2417
prepend: boolean = false,
2518
) => {
2619
if (target) {
2720
const hooks = target[type] || (target[type] = [])
21+
const wrappedHook =
22+
hook.__weh ||
23+
(hook.__weh = (...args: unknown[]) => {
24+
if (target.isUnmounted) {
25+
return
26+
}
27+
pauseTracking()
28+
setCurrentInstance(target)
29+
const res = callWithAsyncErrorHandling(hook, target, type, args)
30+
unsetCurrentInstance()
31+
resetTracking()
32+
return res
33+
})
2834
if (prepend) {
29-
hooks.unshift(hook)
35+
hooks.unshift(wrappedHook)
3036
} else {
31-
hooks.push(hook)
37+
hooks.push(wrappedHook)
3238
}
33-
return hook
39+
return wrappedHook
3440
} else if (__DEV__) {
35-
// TODO: warn need
41+
const apiName = toHandlerKey(ErrorTypeStrings[type].replace(/ hook$/, ''))
42+
warn(
43+
`${apiName} is called when there is no active component instance to be ` +
44+
`associated with. ` +
45+
`Lifecycle injection APIs can only be used during execution of setup().` +
46+
(__FEATURE_SUSPENSE__
47+
? ` If you are using async setup(), make sure to register lifecycle ` +
48+
`hooks before the first await statement.`
49+
: ``),
50+
)
3651
}
3752
}
3853
export const createHook =
@@ -46,3 +61,16 @@ export const onBeforeUpdate = createHook(VaporLifecycleHooks.BEFORE_UPDATE)
4661
export const onUpdated = createHook(VaporLifecycleHooks.UPDATED)
4762
export const onBeforeUnmount = createHook(VaporLifecycleHooks.BEFORE_UNMOUNT)
4863
export const onUnmounted = createHook(VaporLifecycleHooks.UNMOUNTED)
64+
65+
export type ErrorCapturedHook<TError = unknown> = (
66+
err: TError,
67+
instance: ComponentInternalInstance | null,
68+
info: string,
69+
) => boolean | void
70+
71+
export function onErrorCaptured<TError = Error>(
72+
hook: ErrorCapturedHook<TError>,
73+
target: ComponentInternalInstance | null = currentInstance,
74+
) {
75+
injectHook(VaporLifecycleHooks.ERROR_CAPTURED, hook, target)
76+
}

packages/runtime-vapor/src/component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
} from './componentProps'
1111

1212
import type { Data } from '@vue/shared'
13-
import { VaporLifecycleHooks } from './apiLifecycle'
13+
import { VaporLifecycleHooks } from './enums'
1414

1515
export type Component = FunctionalComponent | ObjectComponent
1616

packages/runtime-vapor/src/enums.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
export enum VaporLifecycleHooks {
2+
BEFORE_CREATE = 'bc',
3+
CREATED = 'c',
4+
BEFORE_MOUNT = 'bm',
5+
MOUNTED = 'm',
6+
BEFORE_UPDATE = 'bu',
7+
UPDATED = 'u',
8+
BEFORE_UNMOUNT = 'bum',
9+
UNMOUNTED = 'um',
10+
DEACTIVATED = 'da',
11+
ACTIVATED = 'a',
12+
RENDER_TRIGGERED = 'rtg',
13+
RENDER_TRACKED = 'rtc',
14+
ERROR_CAPTURED = 'ec',
15+
// SERVER_PREFETCH = 'sp',
16+
}

packages/runtime-vapor/src/errorHandling.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
// The ultimate aim is to uncouple this replicated code and
44
// facilitate its shared use between two runtimes.
55

6-
import { VaporLifecycleHooks } from './apiLifecycle'
76
import { type ComponentInternalInstance } from './component'
87
import { isFunction, isPromise } from '@vue/shared'
98
import { warn } from './warning'
9+
import { VaporLifecycleHooks } from './enums'
1010

1111
// contexts where user provided function may be executed, in addition to
1212
// lifecycle hooks.

0 commit comments

Comments
 (0)