import { VNode } from './vnode' ; import { ComponentInternalInstance , LifecycleHooks } from './component' ; import { warn , pushWarningContext , popWarningContext } from './warning' ; import { isPromise , isFunction } from '@vue/shared' ; export const enum ErrorCodes { SETUP_FUNCTION , RENDER_FUNCTION , WATCH_GETTER , WATCH_CALLBACK , WATCH_CLEANUP , NATIVE_EVENT_HANDLER , COMPONENT_EVENT_HANDLER , VNODE_HOOK , DIRECTIVE_HOOK , TRANSITION_HOOK , APP_ERROR_HANDLER , APP_WARN_HANDLER , FUNCTION_REF , ASYNC_COMPONENT_LOADER , SCHEDULER } export const ErrorTypeStrings = { [ LifecycleHooks . SERVER_PREFETCH ] : 'serverPrefetch hook' , [ LifecycleHooks . BEFORE_CREATE ] : 'beforeCreate hook' , [ LifecycleHooks . CREATED ] : 'created hook' , [ LifecycleHooks . BEFORE_MOUNT ] : 'beforeMount hook' , [ LifecycleHooks . MOUNTED ] : 'mounted hook' , [ LifecycleHooks . BEFORE_UPDATE ] : 'beforeUpdate hook' , [ LifecycleHooks . UPDATED ] : 'updated' , [ LifecycleHooks . BEFORE_UNMOUNT ] : 'beforeUnmount hook' , [ LifecycleHooks . UNMOUNTED ] : 'unmounted hook' , [ LifecycleHooks . ACTIVATED ] : 'activated hook' , [ LifecycleHooks . DEACTIVATED ] : 'deactivated hook' , [ LifecycleHooks . ERROR_CAPTURED ] : 'errorCaptured hook' , [ LifecycleHooks . RENDER_TRACKED ] : 'renderTracked hook' , [ LifecycleHooks . RENDER_TRIGGERED ] : 'renderTriggered hook' , [ ErrorCodes . SETUP_FUNCTION ] : 'setup function' , [ ErrorCodes . RENDER_FUNCTION ] : 'render function' , [ ErrorCodes . WATCH_GETTER ] : 'watcher getter' , [ ErrorCodes . WATCH_CALLBACK ] : 'watcher callback' , [ ErrorCodes . WATCH_CLEANUP ] : 'watcher cleanup function' , [ ErrorCodes . NATIVE_EVENT_HANDLER ] : 'native event handler' , [ ErrorCodes . COMPONENT_EVENT_HANDLER ] : 'component event handler' , [ ErrorCodes . VNODE_HOOK ] : 'vnode hook' , [ ErrorCodes . DIRECTIVE_HOOK ] : 'directive hook' , [ ErrorCodes . TRANSITION_HOOK ] : 'transition hook' , [ ErrorCodes . APP_ERROR_HANDLER ] : 'app errorHandler' , [ ErrorCodes . APP_WARN_HANDLER ] : 'app warnHandler' , [ ErrorCodes . FUNCTION_REF ] : 'ref function' , [ ErrorCodes . ASYNC_COMPONENT_LOADER ] : 'async component loader' , [ ErrorCodes . SCHEDULER ] : 'scheduler flush. This is likely a Vue internals bug. ' + 'Please open an issue at https://new-issue.vuejs.org/?repo=vuejs/vue-next' } ; export type ErrorTypes = LifecycleHooks | ErrorCodes ; export function callWithErrorHandling ( fn , instance , type , args ? ) { let res ; try { res = args ? fn ( ... args ) : fn ( ) ; } catch ( err ) { handleError ( err , instance , type ) ; } return res ; } export function callWithAsyncErrorHandling ( fn , instance , type , args ? ) { if ( isFunction ( fn ) ) { const res = callWithErrorHandling ( fn , instance , type , args ) ; if ( res && isPromise ( res ) ) { res . catch ( err => { handleError ( err , instance , type ) ; } ) ; } return res ; } const values = [ ] ; for ( let i = 0 ; i < fn . length ; i ++ ) { values . push ( callWithAsyncErrorHandling ( fn [ i ] , instance , type , args ) ) ; } return values ; } export function handleError ( err , instance , type , throwInDev = true ) { const contextVNode = instance ? instance . vnode : null ; if ( instance ) { let cur = instance . parent ; const exposedInstance = instance . proxy ; const errorInfo = __DEV__ ? ErrorTypeStrings [ type ] : type ; while ( cur ) { const errorCapturedHooks = cur . ec ; if ( errorCapturedHooks ) { for ( let i = 0 ; i < errorCapturedHooks . length ; i ++ ) { if ( errorCapturedHooks [ i ] ( err , exposedInstance , errorInfo ) === false ) { return ; } } } cur = cur . parent ; } const appErrorHandler = instance . appContext . config . errorHandler ; if ( appErrorHandler ) { callWithErrorHandling ( appErrorHandler , null , ErrorCodes . APP_ERROR_HANDLER , [ err , exposedInstance , errorInfo ] ) ; return ; } } logError ( err , type , contextVNode , throwInDev ) ; } function logError ( err , type , contextVNode , throwInDev = true ) { if ( __DEV__ ) { const info = ErrorTypeStrings [ type ] ; if ( contextVNode ) { pushWarningContext ( contextVNode ) ; } warn ( `Unhandled error${ info ? ` during execution of ${ info }` : `` }` ) ; if ( contextVNode ) { popWarningContext ( ) ; } if ( throwInDev ) { throw err ; } else if ( ! __TEST__ ) { console . error ( err ) ; } } else { console . error ( err ) ; } }