fix(runtime-core): error handling for created/beforeCreate hooks
fix #2268
This commit is contained in:
		
							parent
							
								
									d744b8a2dc
								
							
						
					
					
						commit
						b392fe419c
					
				| @ -181,6 +181,41 @@ describe('error handling', () => { | |||||||
|     expect(fn).toHaveBeenCalledWith(err, 'setup function') |     expect(fn).toHaveBeenCalledWith(err, 'setup function') | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
|  |   // unlike other lifecycle hooks, created/beforeCreate are called as part of
 | ||||||
|  |   // the options API initiualization process instead of by the renderer.
 | ||||||
|  |   test('in created/beforeCreate hook', () => { | ||||||
|  |     const err = new Error('foo') | ||||||
|  |     const fn = jest.fn() | ||||||
|  | 
 | ||||||
|  |     const Comp = { | ||||||
|  |       setup() { | ||||||
|  |         onErrorCaptured((err, instance, info) => { | ||||||
|  |           fn(err, info) | ||||||
|  |           return false | ||||||
|  |         }) | ||||||
|  |         return () => [h(Child1), h(Child2)] | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const Child1 = { | ||||||
|  |       created() { | ||||||
|  |         throw err | ||||||
|  |       }, | ||||||
|  |       render() {} | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const Child2 = { | ||||||
|  |       beforeCreate() { | ||||||
|  |         throw err | ||||||
|  |       }, | ||||||
|  |       render() {} | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     render(h(Comp), nodeOps.createElement('div')) | ||||||
|  |     expect(fn).toHaveBeenCalledWith(err, 'created hook') | ||||||
|  |     expect(fn).toHaveBeenCalledWith(err, 'beforeCreate hook') | ||||||
|  |   }) | ||||||
|  | 
 | ||||||
|   test('in render function', () => { |   test('in render function', () => { | ||||||
|     const err = new Error('foo') |     const err = new Error('foo') | ||||||
|     const fn = jest.fn() |     const fn = jest.fn() | ||||||
|  | |||||||
| @ -5,7 +5,8 @@ import { | |||||||
|   ComponentInternalOptions, |   ComponentInternalOptions, | ||||||
|   Component, |   Component, | ||||||
|   ConcreteComponent, |   ConcreteComponent, | ||||||
|   InternalRenderFunction |   InternalRenderFunction, | ||||||
|  |   LifecycleHooks | ||||||
| } from './component' | } from './component' | ||||||
| import { | import { | ||||||
|   isFunction, |   isFunction, | ||||||
| @ -55,6 +56,7 @@ import { | |||||||
| } from './componentPublicInstance' | } from './componentPublicInstance' | ||||||
| import { warn } from './warning' | import { warn } from './warning' | ||||||
| import { VNodeChild } from './vnode' | import { VNodeChild } from './vnode' | ||||||
|  | import { callWithAsyncErrorHandling } from './errorHandling' | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Interface for declaring custom options. |  * Interface for declaring custom options. | ||||||
| @ -472,7 +474,13 @@ export function applyOptions( | |||||||
|   // applyOptions is called non-as-mixin once per instance
 |   // applyOptions is called non-as-mixin once per instance
 | ||||||
|   if (!asMixin) { |   if (!asMixin) { | ||||||
|     isInBeforeCreate = true |     isInBeforeCreate = true | ||||||
|     callSyncHook('beforeCreate', options, publicThis, globalMixins) |     callSyncHook( | ||||||
|  |       'beforeCreate', | ||||||
|  |       LifecycleHooks.BEFORE_CREATE, | ||||||
|  |       options, | ||||||
|  |       instance, | ||||||
|  |       globalMixins | ||||||
|  |     ) | ||||||
|     isInBeforeCreate = false |     isInBeforeCreate = false | ||||||
|     // global mixins are applied first
 |     // global mixins are applied first
 | ||||||
|     applyMixins(instance, globalMixins, deferredData, deferredWatch) |     applyMixins(instance, globalMixins, deferredData, deferredWatch) | ||||||
| @ -662,7 +670,13 @@ export function applyOptions( | |||||||
| 
 | 
 | ||||||
|   // lifecycle options
 |   // lifecycle options
 | ||||||
|   if (!asMixin) { |   if (!asMixin) { | ||||||
|     callSyncHook('created', options, publicThis, globalMixins) |     callSyncHook( | ||||||
|  |       'created', | ||||||
|  |       LifecycleHooks.CREATED, | ||||||
|  |       options, | ||||||
|  |       instance, | ||||||
|  |       globalMixins | ||||||
|  |     ) | ||||||
|   } |   } | ||||||
|   if (beforeMount) { |   if (beforeMount) { | ||||||
|     onBeforeMount(beforeMount.bind(publicThis)) |     onBeforeMount(beforeMount.bind(publicThis)) | ||||||
| @ -707,52 +721,54 @@ export function applyOptions( | |||||||
| 
 | 
 | ||||||
| function callSyncHook( | function callSyncHook( | ||||||
|   name: 'beforeCreate' | 'created', |   name: 'beforeCreate' | 'created', | ||||||
|  |   type: LifecycleHooks, | ||||||
|   options: ComponentOptions, |   options: ComponentOptions, | ||||||
|   ctx: ComponentPublicInstance, |   instance: ComponentInternalInstance, | ||||||
|   globalMixins: ComponentOptions[] |   globalMixins: ComponentOptions[] | ||||||
| ) { | ) { | ||||||
|   callHookFromMixins(name, globalMixins, ctx) |   callHookFromMixins(name, type, globalMixins, instance) | ||||||
| 
 |  | ||||||
|   const { extends: base, mixins } = options |   const { extends: base, mixins } = options | ||||||
|   if (base) { |   if (base) { | ||||||
|     callHookFromExtends(name, base, ctx) |     callHookFromExtends(name, type, base, instance) | ||||||
|   } |   } | ||||||
|   if (mixins) { |   if (mixins) { | ||||||
|     callHookFromMixins(name, mixins, ctx) |     callHookFromMixins(name, type, mixins, instance) | ||||||
|   } |   } | ||||||
|   const selfHook = options[name] |   const selfHook = options[name] | ||||||
|   if (selfHook) { |   if (selfHook) { | ||||||
|     selfHook.call(ctx) |     callWithAsyncErrorHandling(selfHook.bind(instance.proxy!), instance, type) | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function callHookFromExtends( | function callHookFromExtends( | ||||||
|   name: 'beforeCreate' | 'created', |   name: 'beforeCreate' | 'created', | ||||||
|  |   type: LifecycleHooks, | ||||||
|   base: ComponentOptions, |   base: ComponentOptions, | ||||||
|   ctx: ComponentPublicInstance |   instance: ComponentInternalInstance | ||||||
| ) { | ) { | ||||||
|   if (base.extends) { |   if (base.extends) { | ||||||
|     callHookFromExtends(name, base.extends, ctx) |     callHookFromExtends(name, type, base.extends, instance) | ||||||
|   } |   } | ||||||
|   const baseHook = base[name] |   const baseHook = base[name] | ||||||
|   if (baseHook) { |   if (baseHook) { | ||||||
|     baseHook.call(ctx) |     callWithAsyncErrorHandling(baseHook.bind(instance.proxy!), instance, type) | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function callHookFromMixins( | function callHookFromMixins( | ||||||
|   name: 'beforeCreate' | 'created', |   name: 'beforeCreate' | 'created', | ||||||
|  |   type: LifecycleHooks, | ||||||
|   mixins: ComponentOptions[], |   mixins: ComponentOptions[], | ||||||
|   ctx: ComponentPublicInstance |   instance: ComponentInternalInstance | ||||||
| ) { | ) { | ||||||
|   for (let i = 0; i < mixins.length; i++) { |   for (let i = 0; i < mixins.length; i++) { | ||||||
|     const chainedMixins = mixins[i].mixins |     const chainedMixins = mixins[i].mixins | ||||||
|     if (chainedMixins) { |     if (chainedMixins) { | ||||||
|       callHookFromMixins(name, chainedMixins, ctx) |       callHookFromMixins(name, type, chainedMixins, instance) | ||||||
|     } |     } | ||||||
|     const fn = mixins[i][name] |     const fn = mixins[i][name] | ||||||
|     if (fn) { |     if (fn) { | ||||||
|       fn.call(ctx) |       callWithAsyncErrorHandling(fn.bind(instance.proxy!), instance, type) | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user