Improve WASM panic error (#1782)

* Improve WASM panic error

* Add panic test
This commit is contained in:
Drew Powers 2021-11-11 13:04:57 -07:00 committed by GitHub
parent 859b451ca9
commit 3d7d63aa8a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 80 additions and 12 deletions

View file

@ -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, {

View file

@ -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 didnt 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>

View file

@ -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;
}

View file

@ -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 its 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;
}
},

View file

@ -0,0 +1,3 @@
<!-- bad code -->
{[...new Array(20)].map(() => (<div>))}

View 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!');
}
});
});