Improve WASM panic error (#1782)
* Improve WASM panic error * Add panic test
This commit is contained in:
parent
859b451ca9
commit
3d7d63aa8a
6 changed files with 80 additions and 12 deletions
|
@ -178,7 +178,6 @@ export class AstroDevServer {
|
|||
return [];
|
||||
} catch (e) {
|
||||
const err = e as Error;
|
||||
viteServer.ssrFixStacktrace(err);
|
||||
// eslint-disable-next-line
|
||||
console.error(err.stack);
|
||||
viteServer.ws.send({
|
||||
|
@ -302,7 +301,6 @@ export class AstroDevServer {
|
|||
res.write(html);
|
||||
res.end();
|
||||
} catch (err: any) {
|
||||
this.viteServer.ssrFixStacktrace(err);
|
||||
this.viteServer.ws.send({ type: 'error', err });
|
||||
const statusCode = 500;
|
||||
const html = errorTemplate({
|
||||
|
@ -310,6 +308,8 @@ export class AstroDevServer {
|
|||
title: 'Internal Error',
|
||||
tabTitle: '500: Error',
|
||||
message: stripAnsi(err.message),
|
||||
url: err.url || undefined,
|
||||
stack: stripAnsi(err.stack),
|
||||
});
|
||||
info(this.logging, 'astro', msg.req({ url: pathname, statusCode: 500, reqTime: performance.now() - reqStart }));
|
||||
res.writeHead(statusCode, {
|
||||
|
|
|
@ -1,14 +1,23 @@
|
|||
import { encode } from 'html-entities';
|
||||
|
||||
interface ErrorTemplateOptions {
|
||||
statusCode?: number;
|
||||
tabTitle: string;
|
||||
title: string;
|
||||
/** a short description of the error */
|
||||
message: string;
|
||||
/** information about where the error occurred */
|
||||
stack?: string;
|
||||
/** HTTP error code */
|
||||
statusCode?: number;
|
||||
/** HTML <title> */
|
||||
tabTitle: string;
|
||||
/** page title */
|
||||
title: string;
|
||||
/** show user a URL for more info or action to take */
|
||||
url?: string;
|
||||
}
|
||||
|
||||
/** Display internal 404 page (if user didn’t provide one) */
|
||||
export function errorTemplate({ title, message, statusCode, tabTitle }: ErrorTemplateOptions): string {
|
||||
export function errorTemplate({ title, url, message, stack, statusCode, tabTitle }: ErrorTemplateOptions): string {
|
||||
let error = url ? message.replace(url, '') : message;
|
||||
return `<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
|
@ -19,13 +28,16 @@ export function errorTemplate({ title, message, statusCode, tabTitle }: ErrorTem
|
|||
background-color: #101010;
|
||||
color: #d0d0d0;
|
||||
font-family: monospace;
|
||||
line-height: 1.6;
|
||||
line-height: 1.5;
|
||||
margin: 0;
|
||||
}
|
||||
.wrapper {
|
||||
padding-left: 2rem;
|
||||
padding-right: 2rem;
|
||||
}
|
||||
a {
|
||||
color: #ff5d01;
|
||||
}
|
||||
h1 {
|
||||
font-weight: 800;
|
||||
margin-top: 1rem;
|
||||
|
@ -33,7 +45,7 @@ export function errorTemplate({ title, message, statusCode, tabTitle }: ErrorTem
|
|||
}
|
||||
pre {
|
||||
color: #999;
|
||||
font-size: 1.4em;
|
||||
font-size: 1.2em;
|
||||
margin-top: 0;
|
||||
max-width: 60em;
|
||||
}
|
||||
|
@ -45,7 +57,9 @@ export function errorTemplate({ title, message, statusCode, tabTitle }: ErrorTem
|
|||
<body>
|
||||
<main class="wrapper">
|
||||
<h1>${statusCode ? `<span class="statusCode">${statusCode}</span> ` : ''}${title}</h1>
|
||||
<pre><code>${encode(message)}</code></pre>
|
||||
<pre><code>${encode(error)}</code></pre>
|
||||
${url ? `<a target="_blank" href="${url}">${url}</a>` : ''}
|
||||
<pre><code>${encode(stack)}</code></pre>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -81,7 +81,7 @@ async function errorHandler(e: unknown, viteServer: vite.ViteDevServer, filePath
|
|||
const anyError = e as any;
|
||||
if (anyError.errors) {
|
||||
const { location, pluginName, text } = (e as BuildResult).errors[0];
|
||||
const err = new Error(text) as SSRError;
|
||||
const err = e as SSRError;
|
||||
if (location) err.loc = { file: location.file, line: location.line, column: location.column };
|
||||
const frame = codeFrame(await fs.promises.readFile(filePath, 'utf8'), err.loc);
|
||||
err.frame = frame;
|
||||
|
@ -89,7 +89,6 @@ async function errorHandler(e: unknown, viteServer: vite.ViteDevServer, filePath
|
|||
err.message = `${location?.file}: ${text}
|
||||
${frame}
|
||||
`;
|
||||
err.stack = anyError.stack;
|
||||
if (pluginName) err.plugin = pluginName;
|
||||
throw err;
|
||||
}
|
||||
|
|
|
@ -94,7 +94,32 @@ export default function astro({ config, devServer }: AstroPluginOptions): vite.P
|
|||
map,
|
||||
};
|
||||
} catch (err: any) {
|
||||
// if esbuild threw the error, find original code source to display (if it’s mapped)
|
||||
// improve compiler errors
|
||||
if (err.stack.includes('wasm-function')) {
|
||||
const search = new URLSearchParams({
|
||||
labels: 'compiler',
|
||||
title: '🐛 BUG: `@astrojs/compiler` panic',
|
||||
body: `### Describe the Bug
|
||||
|
||||
\`@astrojs/compiler\` encountered an unrecoverable error when compiling the following file.
|
||||
|
||||
**${id.replace(fileURLToPath(config.projectRoot), '')}**
|
||||
\`\`\`astro
|
||||
${source}
|
||||
\`\`\`
|
||||
`,
|
||||
});
|
||||
err.url = `https://github.com/snowpackjs/astro/issues/new?${search.toString()}`;
|
||||
err.message = `Error: Uh oh, the Astro compiler encountered an unrecoverable error!
|
||||
|
||||
Please open
|
||||
a GitHub issue using the link below:
|
||||
${err.url}`;
|
||||
// TODO: remove stack replacement when compiler throws better errors
|
||||
err.stack = ` at ${id}`;
|
||||
}
|
||||
|
||||
// improve esbuild errors
|
||||
if (err.errors && tsResult?.map) {
|
||||
const json = JSON.parse(tsResult.map);
|
||||
const mappings = decode(json.mappings);
|
||||
|
@ -103,6 +128,7 @@ export default function astro({ config, devServer }: AstroPluginOptions): vite.P
|
|||
err.sourceLoc = { file: id, line: (focusMapping[0][2] || 0) + 1, column: (focusMapping[0][3] || 0) + 1 };
|
||||
}
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
|
|
3
packages/astro/test/fixtures/wasm-panic-error/src/pages/index.astro
vendored
Normal file
3
packages/astro/test/fixtures/wasm-panic-error/src/pages/index.astro
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
|
||||
<!-- bad code -->
|
||||
{[...new Array(20)].map(() => (<div>))}
|
26
packages/astro/test/wasm-panic-error.test.js
Normal file
26
packages/astro/test/wasm-panic-error.test.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
import { expect } from 'chai';
|
||||
import cheerio from 'cheerio';
|
||||
import { loadFixture } from './test-utils.js';
|
||||
|
||||
let fixture;
|
||||
|
||||
before(async () => {
|
||||
fixture = await loadFixture({ projectRoot: './fixtures/wasm-panic-error' });
|
||||
});
|
||||
|
||||
describe('compiler error', () => {
|
||||
it('throws helpful error', async () => {
|
||||
try {
|
||||
await fixture.build();
|
||||
|
||||
// should err
|
||||
expect(true).to.be.false;
|
||||
} catch (err) {
|
||||
// test err thrown contains filepath
|
||||
expect(err.stack).to.include('wasm-panic-error/src/pages/index.astro');
|
||||
|
||||
// test err thrown contains "unrecoverable error"
|
||||
expect(err.message || err.toString()).to.include('Uh oh, the Astro compiler encountered an unrecoverable error!');
|
||||
}
|
||||
});
|
||||
});
|
Loading…
Reference in a new issue