Skip to content

fix(core): Report errors to browser global error handler #5029

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions packages/qwik/src/core/error/assert.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { QwikElement, VirtualElement } from '../render/dom/virtual-element';
import { isElement, isQwikElement } from '../util/element';
import { logErrorAndStop } from '../util/log';
import { throwErrorAndStop } from '../util/log';
import { qDev } from '../util/qdev';

const ASSERT_DISCLAIMER = 'Internal assert, this is likely caused by a bug in Qwik: ';
Expand All @@ -14,7 +14,7 @@ export function assertDefined<T>(
if (value != null) {
return;
}
throw logErrorAndStop(ASSERT_DISCLAIMER + text, ...parts);
throwErrorAndStop(ASSERT_DISCLAIMER + text, ...parts);
}
}

Expand All @@ -28,14 +28,14 @@ export function assertEqual(
if (value1 === value2) {
return;
}
throw logErrorAndStop(ASSERT_DISCLAIMER + text, ...parts);
throwErrorAndStop(ASSERT_DISCLAIMER + text, ...parts);
}
}

export function assertFail(text: string, ...parts: any[]): never;
export function assertFail(text: string, ...parts: any[]) {
if (qDev) {
throw logErrorAndStop(ASSERT_DISCLAIMER + text, ...parts);
throwErrorAndStop(ASSERT_DISCLAIMER + text, ...parts);
}
}

Expand All @@ -44,7 +44,7 @@ export function assertTrue(value1: any, text: string, ...parts: any[]): asserts
if (value1 === true) {
return;
}
throw logErrorAndStop(ASSERT_DISCLAIMER + text, ...parts);
throwErrorAndStop(ASSERT_DISCLAIMER + text, ...parts);
}
}

Expand All @@ -53,7 +53,7 @@ export function assertNumber(value1: any, text: string, ...parts: any[]): assert
if (typeof value1 === 'number') {
return;
}
throw logErrorAndStop(ASSERT_DISCLAIMER + text, ...parts);
throwErrorAndStop(ASSERT_DISCLAIMER + text, ...parts);
}
}

Expand All @@ -62,15 +62,15 @@ export function assertString(value1: any, text: string, ...parts: any[]): assert
if (typeof value1 === 'string') {
return;
}
throw logErrorAndStop(ASSERT_DISCLAIMER + text, ...parts);
throwErrorAndStop(ASSERT_DISCLAIMER + text, ...parts);
}
}

export function assertQwikElement(el: any): asserts el is QwikElement {
if (qDev) {
if (!isQwikElement(el)) {
console.error('Not a Qwik Element, got', el);
throw logErrorAndStop(ASSERT_DISCLAIMER + 'Not a Qwik Element');
throwErrorAndStop(ASSERT_DISCLAIMER + 'Not a Qwik Element');
}
}
}
Expand All @@ -79,7 +79,7 @@ export function assertElement(el: Node | VirtualElement): asserts el is Element
if (qDev) {
if (!isElement(el)) {
console.error('Not a Element, got', el);
throw logErrorAndStop(ASSERT_DISCLAIMER + 'Not an Element');
throwErrorAndStop(ASSERT_DISCLAIMER + 'Not an Element');
}
}
}
4 changes: 2 additions & 2 deletions packages/qwik/src/core/state/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
} from '../use/use-task';
import type { QwikElement } from '../render/dom/virtual-element';
import { notifyChange } from '../render/dom/notify-render';
import { createError, logError } from '../util/log';
import { logError, throwErrorAndStop } from '../util/log';
import { tryGetContext } from './context';
import { QObjectFlagsSymbol, QObjectManagerSymbol, QOjectTargetSymbol } from './constants';
import type { Signal } from './signal';
Expand Down Expand Up @@ -101,7 +101,7 @@ const _verifySerializable = <T>(value: T, seen: Set<any>, ctx: string, preMessag
)});\n\nPlease check out https://qwik.builder.io/docs/advanced/qrl/ for more information.`;
}
console.error('Trying to serialize', value);
throw createError(message);
throwErrorAndStop(message);
}
return value;
};
Expand Down
32 changes: 23 additions & 9 deletions packages/qwik/src/core/util/log.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
import type { QwikElement } from '../render/dom/virtual-element';
import type { QContext } from '../state/context';
import { isElement, isNode } from './element';
import { qDev } from './qdev';
import { qDev, qTest } from './qdev';

const STYLE = qDev
? `background: #564CE0; color: white; padding: 2px 3px; border-radius: 2px; font-size: 0.8em;`
: '';

export const logError = (message?: any, ...optionalParams: any[]) => {
const err = message instanceof Error ? message : createError(message);
const messageStr = err.stack || err.message;
console.error('%cQWIK ERROR', STYLE, messageStr, ...printParams(optionalParams));
return err;
return createAndLogError(true, message, ...optionalParams);
};

export const createError = (message?: string) => {
const err = new Error(message);
return err;
export const throwErrorAndStop = (message?: any, ...optionalParams: any[]): never => {
const error = createAndLogError(false, message, ...optionalParams);
// eslint-disable-next-line no-debugger
debugger;
throw error;
};

export const logErrorAndStop = (message?: any, ...optionalParams: any[]) => {
const err = logError(message, ...optionalParams);
const err = createAndLogError(true, message, ...optionalParams);
// eslint-disable-next-line no-debugger
debugger;
return err;
Expand Down Expand Up @@ -79,3 +78,18 @@ const printElement = (el: Element) => {
ctx: isServer ? undefined : ctx,
};
};

const createAndLogError = (asyncThrow: boolean, message?: any, ...optionalParams: any[]) => {
const err = message instanceof Error ? message : new Error(message);
const messageStr = err.stack || err.message;
console.error('%cQWIK ERROR', STYLE, messageStr, ...printParams(optionalParams));
asyncThrow &&
!qTest &&
setTimeout(() => {
// throwing error asynchronously to avoid breaking the current call stack.
// We throw so that the error is delivered to the global error handler for
// reporting it to a third-party tools such as Qwik Insights, Sentry or New Relic.
throw err;
}, 0);
return err;
};