feat: error handling for lifecycle hooks

This commit is contained in:
Evan You
2019-08-30 12:16:09 -04:00
parent fd018b83b5
commit 3d681f8bcd
4 changed files with 225 additions and 54 deletions

View File

@@ -1,51 +1,101 @@
import { ComponentInstance, LifecycleHooks, currentInstance } from './component'
import {
ComponentInstance,
LifecycleHooks,
currentInstance,
setCurrentInstance
} from './component'
import { applyErrorHandling, ErrorTypeStrings } from './errorHandling'
import { warn } from './warning'
import { capitalize } from '@vue/shared'
function injectHook(
name: keyof LifecycleHooks,
type: LifecycleHooks,
hook: Function,
target: ComponentInstance | null | void = currentInstance
target: ComponentInstance | null = currentInstance
) {
if (target) {
// TODO inject a error-handling wrapped version of the hook
// TODO also set currentInstance when calling the hook
;(target[name] || (target[name] = [])).push(hook)
} else {
// TODO warn
// wrap user hook with error handling logic
const withErrorHandling = applyErrorHandling(hook, target, type)
;(target[type] || (target[type] = [])).push((...args: any[]) => {
// Set currentInstance during hook invocation.
// This assumes the hook does not synchronously trigger other hooks, which
// can only be false when the user does something really funky.
setCurrentInstance(target)
const res = withErrorHandling(...args)
setCurrentInstance(null)
return res
})
} else if (__DEV__) {
const apiName = `on${capitalize(
ErrorTypeStrings[name].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().`
)
}
}
export function onBeforeMount(hook: Function, target?: ComponentInstance) {
injectHook('bm', hook, target)
export function onBeforeMount(
hook: Function,
target: ComponentInstance | null = currentInstance
) {
injectHook(LifecycleHooks.BEFORE_MOUNT, hook, target)
}
export function onMounted(hook: Function, target?: ComponentInstance) {
injectHook('m', hook, target)
export function onMounted(
hook: Function,
target: ComponentInstance | null = currentInstance
) {
injectHook(LifecycleHooks.MOUNTED, hook, target)
}
export function onBeforeUpdate(hook: Function, target?: ComponentInstance) {
injectHook('bu', hook, target)
export function onBeforeUpdate(
hook: Function,
target: ComponentInstance | null = currentInstance
) {
injectHook(LifecycleHooks.BEFORE_UPDATE, hook, target)
}
export function onUpdated(hook: Function, target?: ComponentInstance) {
injectHook('u', hook, target)
export function onUpdated(
hook: Function,
target: ComponentInstance | null = currentInstance
) {
injectHook(LifecycleHooks.UPDATED, hook, target)
}
export function onBeforeUnmount(hook: Function, target?: ComponentInstance) {
injectHook('bum', hook, target)
export function onBeforeUnmount(
hook: Function,
target: ComponentInstance | null = currentInstance
) {
injectHook(LifecycleHooks.BEFORE_UNMOUNT, hook, target)
}
export function onUnmounted(hook: Function, target?: ComponentInstance) {
injectHook('um', hook, target)
export function onUnmounted(
hook: Function,
target: ComponentInstance | null = currentInstance
) {
injectHook(LifecycleHooks.UNMOUNTED, hook, target)
}
export function onRenderTriggered(hook: Function, target?: ComponentInstance) {
injectHook('rtg', hook, target)
export function onRenderTriggered(
hook: Function,
target: ComponentInstance | null = currentInstance
) {
injectHook(LifecycleHooks.RENDER_TRIGGERED, hook, target)
}
export function onRenderTracked(hook: Function, target?: ComponentInstance) {
injectHook('rtc', hook, target)
export function onRenderTracked(
hook: Function,
target: ComponentInstance | null = currentInstance
) {
injectHook(LifecycleHooks.RENDER_TRACKED, hook, target)
}
export function onErrorCaptured(hook: Function, target?: ComponentInstance) {
injectHook('ec', hook, target)
export function onErrorCaptured(
hook: Function,
target: ComponentInstance | null = currentInstance
) {
injectHook(LifecycleHooks.ERROR_CAPTURED, hook, target)
}