mirror of https://github.com/vuejs/core.git
fix(runtime-core): errors during component patch should be caught by error handlers
This commit is contained in:
parent
3d34f406ac
commit
ee0248accf
|
@ -1,4 +1,5 @@
|
|||
import {
|
||||
type VNode,
|
||||
createApp,
|
||||
defineComponent,
|
||||
h,
|
||||
|
@ -11,6 +12,7 @@ import {
|
|||
watch,
|
||||
watchEffect,
|
||||
} from '@vue/runtime-test'
|
||||
import { ErrorCodes, ErrorTypeStrings } from '../src/errorHandling'
|
||||
|
||||
describe('error handling', () => {
|
||||
test('propagation', () => {
|
||||
|
@ -609,5 +611,33 @@ describe('error handling', () => {
|
|||
expect(handler).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
test('errors in scheduler job with owner instance should be caught', async () => {
|
||||
let vnode: VNode
|
||||
const x = ref(0)
|
||||
const app = createApp({
|
||||
render() {
|
||||
return (vnode = vnode || h('div', x.value))
|
||||
},
|
||||
})
|
||||
|
||||
app.config.errorHandler = vi.fn()
|
||||
app.mount(nodeOps.createElement('div'))
|
||||
|
||||
const error = new Error('error')
|
||||
Object.defineProperty(vnode!, 'el', {
|
||||
get() {
|
||||
throw error
|
||||
},
|
||||
})
|
||||
|
||||
x.value++
|
||||
await nextTick()
|
||||
expect(app.config.errorHandler).toHaveBeenCalledWith(
|
||||
error,
|
||||
{},
|
||||
ErrorTypeStrings[ErrorCodes.COMPONENT_UPDATE],
|
||||
)
|
||||
})
|
||||
|
||||
// native event handler handling should be tested in respective renderers
|
||||
})
|
||||
|
|
|
@ -23,6 +23,7 @@ export enum ErrorCodes {
|
|||
FUNCTION_REF,
|
||||
ASYNC_COMPONENT_LOADER,
|
||||
SCHEDULER,
|
||||
COMPONENT_UPDATE,
|
||||
}
|
||||
|
||||
export const ErrorTypeStrings: Record<LifecycleHooks | ErrorCodes, string> = {
|
||||
|
@ -54,16 +55,15 @@ export const ErrorTypeStrings: Record<LifecycleHooks | ErrorCodes, string> = {
|
|||
[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://github.com/vuejs/core .',
|
||||
[ErrorCodes.SCHEDULER]: 'scheduler flush',
|
||||
[ErrorCodes.COMPONENT_UPDATE]: 'component update',
|
||||
}
|
||||
|
||||
export type ErrorTypes = LifecycleHooks | ErrorCodes
|
||||
|
||||
export function callWithErrorHandling(
|
||||
fn: Function,
|
||||
instance: ComponentInternalInstance | null,
|
||||
instance: ComponentInternalInstance | null | undefined,
|
||||
type: ErrorTypes,
|
||||
args?: unknown[],
|
||||
) {
|
||||
|
@ -105,7 +105,7 @@ export function callWithAsyncErrorHandling(
|
|||
|
||||
export function handleError(
|
||||
err: unknown,
|
||||
instance: ComponentInternalInstance | null,
|
||||
instance: ComponentInternalInstance | null | undefined,
|
||||
type: ErrorTypes,
|
||||
throwInDev = true,
|
||||
) {
|
||||
|
|
|
@ -1587,6 +1587,7 @@ function baseCreateRenderer(
|
|||
effect.run()
|
||||
}
|
||||
})
|
||||
update.i = instance
|
||||
update.id = instance.uid
|
||||
// allowRecurse
|
||||
// #1801, #2043 component render effects should allow recursive updates
|
||||
|
@ -1599,7 +1600,6 @@ function baseCreateRenderer(
|
|||
effect.onTrigger = instance.rtg
|
||||
? e => invokeArrayFns(instance.rtg!, e)
|
||||
: void 0
|
||||
update.ownerInstance = instance
|
||||
}
|
||||
|
||||
update()
|
||||
|
|
|
@ -26,9 +26,8 @@ export interface SchedulerJob extends Function {
|
|||
/**
|
||||
* Attached by renderer.ts when setting up a component's render effect
|
||||
* Used to obtain component information when reporting max recursive updates.
|
||||
* dev only.
|
||||
*/
|
||||
ownerInstance?: ComponentInternalInstance
|
||||
i?: ComponentInternalInstance
|
||||
}
|
||||
|
||||
export type SchedulerJobs = SchedulerJob | SchedulerJob[]
|
||||
|
@ -240,7 +239,11 @@ function flushJobs(seen?: CountMap) {
|
|||
if (__DEV__ && check(job)) {
|
||||
continue
|
||||
}
|
||||
callWithErrorHandling(job, null, ErrorCodes.SCHEDULER)
|
||||
callWithErrorHandling(
|
||||
job,
|
||||
job.i,
|
||||
job.i ? ErrorCodes.COMPONENT_UPDATE : ErrorCodes.SCHEDULER,
|
||||
)
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
|
@ -265,7 +268,7 @@ function checkRecursiveUpdates(seen: CountMap, fn: SchedulerJob) {
|
|||
} else {
|
||||
const count = seen.get(fn)!
|
||||
if (count > RECURSION_LIMIT) {
|
||||
const instance = fn.ownerInstance
|
||||
const instance = fn.i
|
||||
const componentName = instance && getComponentName(instance.type)
|
||||
handleError(
|
||||
`Maximum recursive updates exceeded${
|
||||
|
|
Loading…
Reference in New Issue