mirror of
https://github.com/withastro/astro.git
synced 2025-03-10 23:01:26 -05:00
Prevent throwing in react and solid component checks (#11624)
This commit is contained in:
parent
cc405dd1fe
commit
7adb350a37
7 changed files with 36 additions and 53 deletions
5
.changeset/few-starfishes-change.md
Normal file
5
.changeset/few-starfishes-change.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'@astrojs/solid-js': patch
|
||||
---
|
||||
|
||||
Prevents throwing errors when checking if a component is a Solid component in runtime
|
5
.changeset/spotty-lies-eat.md
Normal file
5
.changeset/spotty-lies-eat.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'@astrojs/react': patch
|
||||
---
|
||||
|
||||
Prevents throwing errors when checking if a component is a React component in runtime
|
|
@ -67,15 +67,18 @@ test.describe('Error display', () => {
|
|||
expect(fileLocation).toMatch(/^pages\/import-not-found\.astro/);
|
||||
});
|
||||
|
||||
// NOTE: It's not possible to detect some JSX components if they have errors because
|
||||
// their renderers' check functions run the render directly, and if a runtime error is
|
||||
// thrown, it assumes that it's simply not that renderer's component and skips it
|
||||
test('shows correct file path when a component has an error', async ({ page, astro }) => {
|
||||
await page.goto(astro.resolveUrl('/preact-runtime-error'), { waitUntil: 'networkidle' });
|
||||
await page.goto(astro.resolveUrl('/vue-runtime-error'), { waitUntil: 'networkidle' });
|
||||
|
||||
const { fileLocation, absoluteFileLocation } = await getErrorOverlayContent(page);
|
||||
const absoluteFileUrl = 'file://' + absoluteFileLocation.replace(/:\d+:\d+$/, '');
|
||||
const fileExists = astro.pathExists(absoluteFileUrl);
|
||||
|
||||
expect(fileExists).toBeTruthy();
|
||||
expect(fileLocation).toMatch(/^preact\/PreactRuntimeError.jsx/);
|
||||
expect(fileLocation).toMatch(/^vue\/VueRuntimeError.vue/);
|
||||
});
|
||||
|
||||
test('shows correct line when a style preprocess has an error', async ({ page, astro }) => {
|
||||
|
|
|
@ -27,19 +27,17 @@ async function check(
|
|||
useConsoleFilter();
|
||||
|
||||
try {
|
||||
try {
|
||||
const { html } = await renderToStaticMarkup.call(this, Component, props, children, undefined);
|
||||
if (typeof html !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// There are edge cases (SolidJS) where Preact *might* render a string,
|
||||
// but components would be <undefined></undefined>
|
||||
// It also might render an empty sting.
|
||||
return html == '' ? false : !html.includes('<undefined>');
|
||||
} catch {
|
||||
const { html } = await renderToStaticMarkup.call(this, Component, props, children, undefined);
|
||||
if (typeof html !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// There are edge cases (SolidJS) where Preact *might* render a string,
|
||||
// but components would be <undefined></undefined>
|
||||
// It also might render an empty sting.
|
||||
return html == '' ? false : !html.includes('<undefined>');
|
||||
} catch {
|
||||
return false;
|
||||
} finally {
|
||||
finishUsingConsoleFilter();
|
||||
}
|
||||
|
|
|
@ -5,14 +5,6 @@ import StaticHtml from './static-html.js';
|
|||
const slotName = (str) => str.trim().replace(/[-_]([a-z])/g, (_, w) => w.toUpperCase());
|
||||
const reactTypeof = Symbol.for('react.element');
|
||||
|
||||
function errorIsComingFromPreactComponent(err) {
|
||||
return (
|
||||
err.message &&
|
||||
(err.message.startsWith("Cannot read property '__H'") ||
|
||||
err.message.includes("(reading '__H')"))
|
||||
);
|
||||
}
|
||||
|
||||
function check(Component, props, children) {
|
||||
// Note: there are packages that do some unholy things to create "components".
|
||||
// Checking the $$typeof property catches most of these patterns.
|
||||
|
@ -26,7 +18,6 @@ function check(Component, props, children) {
|
|||
return React.Component.isPrototypeOf(Component) || React.PureComponent.isPrototypeOf(Component);
|
||||
}
|
||||
|
||||
let error = null;
|
||||
let isReactComponent = false;
|
||||
function Tester(...args) {
|
||||
try {
|
||||
|
@ -34,20 +25,13 @@ function check(Component, props, children) {
|
|||
if (vnode && vnode['$$typeof'] === reactTypeof) {
|
||||
isReactComponent = true;
|
||||
}
|
||||
} catch (err) {
|
||||
if (!errorIsComingFromPreactComponent(err)) {
|
||||
error = err;
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
|
||||
return React.createElement('div');
|
||||
}
|
||||
|
||||
renderToStaticMarkup(Tester, props, children, {});
|
||||
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
return isReactComponent;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,14 +7,6 @@ import StaticHtml from './static-html.js';
|
|||
const slotName = (str) => str.trim().replace(/[-_]([a-z])/g, (_, w) => w.toUpperCase());
|
||||
const reactTypeof = Symbol.for('react.element');
|
||||
|
||||
function errorIsComingFromPreactComponent(err) {
|
||||
return (
|
||||
err.message &&
|
||||
(err.message.startsWith("Cannot read property '__H'") ||
|
||||
err.message.includes("(reading '__H')"))
|
||||
);
|
||||
}
|
||||
|
||||
async function check(Component, props, children) {
|
||||
// Note: there are packages that do some unholy things to create "components".
|
||||
// Checking the $$typeof property catches most of these patterns.
|
||||
|
@ -32,7 +24,6 @@ async function check(Component, props, children) {
|
|||
return React.Component.isPrototypeOf(Component) || React.PureComponent.isPrototypeOf(Component);
|
||||
}
|
||||
|
||||
let error = null;
|
||||
let isReactComponent = false;
|
||||
function Tester(...args) {
|
||||
try {
|
||||
|
@ -40,20 +31,13 @@ async function check(Component, props, children) {
|
|||
if (vnode && vnode['$$typeof'] === reactTypeof) {
|
||||
isReactComponent = true;
|
||||
}
|
||||
} catch (err) {
|
||||
if (!errorIsComingFromPreactComponent(err)) {
|
||||
error = err;
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
|
||||
return React.createElement('div');
|
||||
}
|
||||
|
||||
await renderToStaticMarkup(Tester, props, children, {});
|
||||
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
return isReactComponent;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,12 +28,16 @@ async function check(
|
|||
// In general, components from other frameworks (eg, MDX, React, etc.) tend to render as "undefined",
|
||||
// so we take advantage of this trick to decide if this is a Solid component or not.
|
||||
|
||||
const { html } = await renderToStaticMarkup.call(this, Component, props, children, {
|
||||
// The purpose of check() is just to validate that this is a Solid component and not
|
||||
// React, etc. We should render in sync mode which should skip Suspense boundaries
|
||||
// or loading resources like external API calls.
|
||||
renderStrategy: 'sync' as RenderStrategy,
|
||||
});
|
||||
let html: string | undefined;
|
||||
try {
|
||||
const result = await renderToStaticMarkup.call(this, Component, props, children, {
|
||||
// The purpose of check() is just to validate that this is a Solid component and not
|
||||
// React, etc. We should render in sync mode which should skip Suspense boundaries
|
||||
// or loading resources like external API calls.
|
||||
renderStrategy: 'sync' as RenderStrategy,
|
||||
});
|
||||
html = result.html;
|
||||
} catch {}
|
||||
|
||||
return typeof html === 'string';
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue