| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- import { ComponentInstance } from './component'
- import { warn, pushWarningContext, popWarningContext } from './warning'
- import { VNode } from './vdom'
- import { VNodeFlags } from './flags'
- export const enum ErrorTypes {
- BEFORE_CREATE = 1,
- CREATED,
- BEFORE_MOUNT,
- MOUNTED,
- BEFORE_UPDATE,
- UPDATED,
- BEFORE_UNMOUNT,
- UNMOUNTED,
- ACTIVATED,
- DEACTIVATED,
- ERROR_CAPTURED,
- RENDER,
- RENDER_TRACKED,
- RENDER_TRIGGERED,
- WATCH_CALLBACK,
- NATIVE_EVENT_HANDLER,
- COMPONENT_EVENT_HANDLER,
- SCHEDULER
- }
- const ErrorTypeStrings: Record<number, string> = {
- [ErrorTypes.BEFORE_CREATE]: 'in beforeCreate lifecycle hook',
- [ErrorTypes.CREATED]: 'in created lifecycle hook',
- [ErrorTypes.BEFORE_MOUNT]: 'in beforeMount lifecycle hook',
- [ErrorTypes.MOUNTED]: 'in mounted lifecycle hook',
- [ErrorTypes.BEFORE_UPDATE]: 'in beforeUpdate lifecycle hook',
- [ErrorTypes.UPDATED]: 'in updated lifecycle hook',
- [ErrorTypes.BEFORE_UNMOUNT]: 'in beforeUnmount lifecycle hook',
- [ErrorTypes.UNMOUNTED]: 'in unmounted lifecycle hook',
- [ErrorTypes.ACTIVATED]: 'in activated lifecycle hook',
- [ErrorTypes.DEACTIVATED]: 'in deactivated lifecycle hook',
- [ErrorTypes.ERROR_CAPTURED]: 'in errorCaptured lifecycle hook',
- [ErrorTypes.RENDER]: 'in render function',
- [ErrorTypes.RENDER_TRACKED]: 'in renderTracked debug hook',
- [ErrorTypes.RENDER_TRIGGERED]: 'in renderTriggered debug hook',
- [ErrorTypes.WATCH_CALLBACK]: 'in watcher callback',
- [ErrorTypes.NATIVE_EVENT_HANDLER]: 'in native event handler',
- [ErrorTypes.COMPONENT_EVENT_HANDLER]: 'in component event handler',
- [ErrorTypes.SCHEDULER]:
- 'when flushing updates. This may be a Vue internals bug.'
- }
- export function callLifecycleHookWithHandler(
- hook: Function,
- instanceProxy: ComponentInstance,
- type: ErrorTypes,
- arg?: any
- ) {
- try {
- const res = hook.call(instanceProxy, arg)
- if (res && typeof res.then === 'function') {
- ;(res as Promise<any>).catch(err => {
- handleError(err, instanceProxy._self, type)
- })
- }
- } catch (err) {
- handleError(err, instanceProxy._self, type)
- }
- }
- export function handleError(
- err: Error,
- instance: ComponentInstance | VNode | null,
- type: ErrorTypes
- ) {
- const isFunctional = instance && (instance as VNode)._isVNode
- const contextVNode =
- instance &&
- ((isFunctional
- ? instance
- : (instance as ComponentInstance).$parentVNode) as VNode | null)
- let cur: ComponentInstance | null = null
- if (isFunctional) {
- let vnode = instance as VNode | null
- while (vnode && !(vnode.flags & VNodeFlags.COMPONENT_STATEFUL)) {
- vnode = vnode.contextVNode
- }
- if (vnode) {
- cur = vnode.children as ComponentInstance
- }
- } else if (instance) {
- cur = (instance as ComponentInstance).$parent
- }
- while (cur) {
- cur = cur._self
- const handler = cur.errorCaptured
- if (handler) {
- try {
- const captured = handler.call(
- cur,
- err,
- type,
- isFunctional ? null : instance
- )
- if (captured) return
- } catch (err2) {
- logError(err2, ErrorTypes.ERROR_CAPTURED, contextVNode)
- }
- }
- cur = cur.$parent
- }
- logError(err, type, contextVNode)
- }
- function logError(err: Error, type: ErrorTypes, contextVNode: VNode | null) {
- if (__DEV__) {
- const info = ErrorTypeStrings[type]
- if (contextVNode) {
- pushWarningContext(contextVNode)
- }
- warn(`Unhandled error${info ? ` ${info}` : ``}`)
- if (contextVNode) {
- popWarningContext()
- }
- console.error(err)
- } else {
- throw err
- }
- }
|