mirror of https://github.com/vuejs/core.git
feat(runtime-core): add app.config.throwUnhandledErrorInProduction
close #7876
This commit is contained in:
parent
912494318f
commit
f476b7f030
|
|
@ -538,6 +538,23 @@ describe('api: createApp', () => {
|
||||||
expect(serializeInner(root)).toBe('hello')
|
expect(serializeInner(root)).toBe('hello')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('config.throwUnhandledErrorInProduction', () => {
|
||||||
|
__DEV__ = false
|
||||||
|
try {
|
||||||
|
const err = new Error()
|
||||||
|
const app = createApp({
|
||||||
|
setup() {
|
||||||
|
throw err
|
||||||
|
},
|
||||||
|
})
|
||||||
|
app.config.throwUnhandledErrorInProduction = true
|
||||||
|
const root = nodeOps.createElement('div')
|
||||||
|
expect(() => app.mount(root)).toThrow(err)
|
||||||
|
} finally {
|
||||||
|
__DEV__ = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
test('return property "_" should not overwrite "ctx._", __isScriptSetup: false', () => {
|
test('return property "_" should not overwrite "ctx._", __isScriptSetup: false', () => {
|
||||||
const Comp = defineComponent({
|
const Comp = defineComponent({
|
||||||
setup() {
|
setup() {
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,13 @@ export interface AppConfig {
|
||||||
* Enable warnings for computed getters that recursively trigger itself.
|
* Enable warnings for computed getters that recursively trigger itself.
|
||||||
*/
|
*/
|
||||||
warnRecursiveComputed?: boolean
|
warnRecursiveComputed?: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to throw unhandled errors in production.
|
||||||
|
* Default is `false` to avoid crashing on any error (and only logs it)
|
||||||
|
* But in some cases, e.g. SSR, throwing might be more desirable.
|
||||||
|
*/
|
||||||
|
throwUnhandledErrorInProduction?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AppContext {
|
export interface AppContext {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { pauseTracking, resetTracking } from '@vue/reactivity'
|
||||||
import type { VNode } from './vnode'
|
import type { VNode } from './vnode'
|
||||||
import type { ComponentInternalInstance } from './component'
|
import type { ComponentInternalInstance } from './component'
|
||||||
import { popWarningContext, pushWarningContext, warn } from './warning'
|
import { popWarningContext, pushWarningContext, warn } from './warning'
|
||||||
import { isArray, isFunction, isPromise } from '@vue/shared'
|
import { EMPTY_OBJ, isArray, isFunction, isPromise } from '@vue/shared'
|
||||||
import { LifecycleHooks } from './enums'
|
import { LifecycleHooks } from './enums'
|
||||||
|
|
||||||
// contexts where user provided function may be executed, in addition to
|
// contexts where user provided function may be executed, in addition to
|
||||||
|
|
@ -111,7 +111,9 @@ export function handleError(
|
||||||
type: ErrorTypes,
|
type: ErrorTypes,
|
||||||
throwInDev = true,
|
throwInDev = true,
|
||||||
) {
|
) {
|
||||||
const contextVNode = instance ? instance.vnode : null
|
const contextVNode = instance && instance.vnode
|
||||||
|
const { errorHandler, throwUnhandledErrorInProduction } =
|
||||||
|
(instance && instance.appContext.config) || EMPTY_OBJ
|
||||||
if (instance) {
|
if (instance) {
|
||||||
let cur = instance.parent
|
let cur = instance.parent
|
||||||
// the exposed instance is the render proxy to keep it consistent with 2.x
|
// the exposed instance is the render proxy to keep it consistent with 2.x
|
||||||
|
|
@ -134,20 +136,18 @@ export function handleError(
|
||||||
cur = cur.parent
|
cur = cur.parent
|
||||||
}
|
}
|
||||||
// app-level handling
|
// app-level handling
|
||||||
const appErrorHandler = instance.appContext.config.errorHandler
|
if (errorHandler) {
|
||||||
if (appErrorHandler) {
|
|
||||||
pauseTracking()
|
pauseTracking()
|
||||||
callWithErrorHandling(
|
callWithErrorHandling(errorHandler, null, ErrorCodes.APP_ERROR_HANDLER, [
|
||||||
appErrorHandler,
|
err,
|
||||||
null,
|
exposedInstance,
|
||||||
ErrorCodes.APP_ERROR_HANDLER,
|
errorInfo,
|
||||||
[err, exposedInstance, errorInfo],
|
])
|
||||||
)
|
|
||||||
resetTracking()
|
resetTracking()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logError(err, type, contextVNode, throwInDev)
|
logError(err, type, contextVNode, throwInDev, throwUnhandledErrorInProduction)
|
||||||
}
|
}
|
||||||
|
|
||||||
function logError(
|
function logError(
|
||||||
|
|
@ -155,6 +155,7 @@ function logError(
|
||||||
type: ErrorTypes,
|
type: ErrorTypes,
|
||||||
contextVNode: VNode | null,
|
contextVNode: VNode | null,
|
||||||
throwInDev = true,
|
throwInDev = true,
|
||||||
|
throwInProd = false,
|
||||||
) {
|
) {
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
const info = ErrorTypeStrings[type]
|
const info = ErrorTypeStrings[type]
|
||||||
|
|
@ -171,6 +172,8 @@ function logError(
|
||||||
} else if (!__TEST__) {
|
} else if (!__TEST__) {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
}
|
}
|
||||||
|
} else if (throwInProd) {
|
||||||
|
throw err
|
||||||
} else {
|
} else {
|
||||||
// recover in prod to reduce the impact on end-user
|
// recover in prod to reduce the impact on end-user
|
||||||
console.error(err)
|
console.error(err)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue