Skip to content

Commit

Permalink
fix(runtime): don't render when crashing (#2746)
Browse files Browse the repository at this point in the history
  • Loading branch information
manucorporat authored Nov 19, 2020
1 parent 24db71b commit c91e0c8
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 21 deletions.
3 changes: 2 additions & 1 deletion src/client/client-log.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type * as d from '../declarations';
import { BUILD } from '@app-data';

let customError: d.ErrorHandler ;
let customError: d.ErrorHandler;

export const consoleError: d.ErrorHandler = (e: any, el?: any) => (customError || console.error)(e, el);

export const STENCIL_DEV_MODE = BUILD.isTesting
Expand Down
8 changes: 7 additions & 1 deletion src/hydrate/platform/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type * as d from '../../declarations';
import { addHostEventListeners } from '@runtime';

let customError: d.ErrorHandler;

export const cmpModules = new Map<string, { [exportName: string]: d.ComponentConstructor }>();

const getModule = (tagName: string): d.ComponentConstructor => {
Expand Down Expand Up @@ -71,12 +73,14 @@ export const writeTask = (cb: Function) => {
const resolved = /*@__PURE__*/ Promise.resolve();
export const nextTick = /*@__PURE__*/ (cb: () => void) => resolved.then(cb);

export const consoleError = (e: any) => {
const defaultConsoleError = (e: any) => {
if (e != null) {
console.error(e.stack || e.message || e);
}
};

export const consoleError: d.ErrorHandler = (e: any, el?: any) => (customError || defaultConsoleError)(e, el);

export const consoleDevError = (..._: any[]) => {
/* noop for hydrate */
};
Expand All @@ -89,6 +93,8 @@ export const consoleDevInfo = (..._: any[]) => {
/* noop for hydrate */
};

export const setErrorHandler = (handler: d.ErrorHandler) => customError = handler;

/*hydrate context start*/ export const Context = {}; /*hydrate context end*/

export const plt: d.PlatformRuntime = {
Expand Down
38 changes: 37 additions & 1 deletion src/runtime/test/render-vdom.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, Element, Host, Prop, State, forceUpdate, getRenderingRef, h } from '@stencil/core';
import { Component, Element, setErrorHandler, Host, Prop, State, forceUpdate, getRenderingRef, h } from '@stencil/core';
import { newSpecPage } from '@stencil/core/testing';

describe('render-vdom', () => {
Expand Down Expand Up @@ -465,6 +465,42 @@ describe('render-vdom', () => {
`);
});

it('render crash should not remove the content', async () => {
let didError = false;
setErrorHandler((err) => {
didError = true;
});
@Component({ tag: 'cmp-a' })
class CmpA {
@Prop() crash = false;
render() {
if (this.crash) {
throw new Error('YOLO');
}
return <div>Hello</div>;
}
}

const { root, waitForChanges } = await newSpecPage({
components: [CmpA],

html: `<cmp-a></cmp-a>`,
});

expect(root).toEqualHtml(`
<cmp-a><div>Hello</div></cmp-a>
`);

expect(didError).toBe(false);
root.crash = true;
await waitForChanges();

expect(root).toEqualHtml(`
<cmp-a><div>Hello</div></cmp-a>
`);
expect(didError).toBe(true);
});

it('Hello VDOM, html option', async () => {
@Component({ tag: 'cmp-a' })
class CmpA {
Expand Down
35 changes: 20 additions & 15 deletions src/runtime/update-component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,19 +81,10 @@ const updateComponent = async (hostRef: d.HostRef, instance: any, isInitialLoad:
hostRef.$flags$ |= HOST_FLAGS.devOnRender;
}

if (BUILD.hasRenderFn || BUILD.reflect) {
if (BUILD.vdomRender || BUILD.reflect) {
// looks like we've got child nodes to render into this host element
// or we need to update the css class/attrs on the host element
// DOM WRITE!
if (BUILD.hydrateServerSide) {
renderVdom(hostRef, await callRender(hostRef, instance));
} else {
renderVdom(hostRef, callRender(hostRef, instance));
}
} else {
elm.textContent = callRender(hostRef, instance);
}
if (BUILD.hydrateServerSide) {
await callRender(hostRef, instance, elm);
} else {
callRender(hostRef, instance, elm);
}
if (BUILD.cssVarShim && plt.$cssShim$) {
plt.$cssShim$.updateHost(elm);
Expand Down Expand Up @@ -149,7 +140,7 @@ const updateComponent = async (hostRef: d.HostRef, instance: any, isInitialLoad:

let renderingRef: any = null;

const callRender = (hostRef: d.HostRef, instance: any) => {
const callRender = (hostRef: d.HostRef, instance: any, elm: HTMLElement) => {
// in order for bundlers to correctly treeshake the BUILD object
// we need to ensure BUILD is not deoptimized within a try/catch
// https://rollupjs.org/guide/en/#treeshake tryCatchDeoptimization
Expand All @@ -169,11 +160,25 @@ const callRender = (hostRef: d.HostRef, instance: any) => {
if (updatable || lazyLoad) {
hostRef.$flags$ |= HOST_FLAGS.hasRendered;
}
if (BUILD.hasRenderFn || BUILD.reflect) {
if (BUILD.vdomRender || BUILD.reflect) {
// looks like we've got child nodes to render into this host element
// or we need to update the css class/attrs on the host element
// DOM WRITE!
if (BUILD.hydrateServerSide) {
return Promise.resolve(instance).then(value => renderVdom(hostRef, value))
} else {
renderVdom(hostRef, instance);
}
} else {
elm.textContent = instance;
}
}
} catch (e) {
consoleError(e, hostRef.$hostElement$);
}
renderingRef = null;
return instance;
return null;
};

export const getRenderingRef = () => renderingRef;
Expand Down
3 changes: 2 additions & 1 deletion src/testing/jest/jest-setup-test-framework.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { setupGlobal, teardownGlobal } from '@stencil/core/mock-doc';
import { setupMockFetch } from '../mock-fetch';
import { HtmlSerializer } from './jest-serializer';
import { resetBuildConditionals } from '../reset-build-conditionals';
import { resetPlatform, stopAutoApplyChanges, modeResolutionChain } from '@stencil/core/internal/testing';
import { resetPlatform, stopAutoApplyChanges, modeResolutionChain, setErrorHandler } from '@stencil/core/internal/testing';

declare const global: d.JestEnvironmentGlobal;

Expand All @@ -22,6 +22,7 @@ export function jestSetupTestFramework() {
beforeEach(() => {
// reset the platform for this new test
resetPlatform();
setErrorHandler(undefined);
resetBuildConditionals(BUILD);
modeResolutionChain.length = 0;
});
Expand Down
2 changes: 1 addition & 1 deletion src/testing/platform/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export { Build } from './testing-build';
export { Env } from '@app-data';
export { consoleDevError, consoleDevInfo, consoleDevWarn, consoleError } from './testing-log';
export { consoleDevError, consoleDevInfo, consoleDevWarn, consoleError, setErrorHandler } from './testing-log';
export {
Context,
isMemberInElement,
Expand Down
10 changes: 9 additions & 1 deletion src/testing/platform/testing-log.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import type * as d from '../../declarations';
import { caughtErrors } from './testing-constants';

export const consoleError = (e: any) => {
let customError: d.ErrorHandler;

const defaultConsoleError = (e: any) => {
console.log('here', customError);
caughtErrors.push(e);
};

export const consoleError: d.ErrorHandler = (e: any, el?: any) => (customError || defaultConsoleError)(e, el);

export const consoleDevError = (...e: any[]) => {
caughtErrors.push(new Error(e.join(', ')));
};
Expand All @@ -15,3 +21,5 @@ export const consoleDevWarn = (..._: any[]) => {
export const consoleDevInfo = (..._: any[]) => {
/* noop for testing */
};

export const setErrorHandler = (handler: d.ErrorHandler) => customError = handler;
1 change: 1 addition & 0 deletions src/testing/platform/testing-platform.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type * as d from '@stencil/core/internal';
import { cstrs, hostRefs, moduleLoaded, styles } from './testing-constants';
import { setErrorHandler } from './testing-log';
import { flushAll, resetTaskQueue } from './testing-task-queue';
import { win } from './testing-window';

Expand Down

0 comments on commit c91e0c8

Please sign in to comment.