0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2025-04-07 23:41:43 -05:00

Prevent errors in rendering from crashing server (#10221)

* Prevent errors in rendering from crashing server

* Add changeset

* Make the reject an error

* Simplify

* Update .changeset/breezy-pears-admire.md

Co-authored-by: Florian Lefebvre <contact@florian-lefebvre.dev>

---------

Co-authored-by: Florian Lefebvre <contact@florian-lefebvre.dev>
This commit is contained in:
Matthew Phillips 2024-02-26 03:36:43 -05:00 committed by GitHub
parent 84502b4190
commit 4db82d9c7d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 78 additions and 14 deletions

View file

@ -0,0 +1,5 @@
---
"astro": patch
---
Prevents errors in templates from crashing the server

View file

@ -174,6 +174,9 @@ export function renderToBufferDestination(bufferRenderFunction: RenderFunction):
// Don't await for the render to finish to not block streaming
const renderPromise = bufferRenderFunction(bufferDestination);
// Catch here in case it throws before `renderToFinalDestination` is called,
// to prevent an unhandled rejection.
Promise.resolve(renderPromise).catch(() => {});
// Return a closure that writes the buffered chunk
return {

View file

@ -1,37 +1,64 @@
import assert from 'node:assert/strict';
import { after, before, describe, it } from 'node:test';
import { loadFixture } from './test-utils.js';
import testAdapter from './test-adapter.js';
describe('Errors in JavaScript', () => {
/** @type {import('./test-utils').Fixture} */
let fixture;
/** @type {import('./test-utils').DevServer} */
let devServer;
before(async () => {
fixture = await loadFixture({
output: 'server',
adapter: testAdapter(),
root: './fixtures/error-bad-js',
vite: {
logLevel: 'silent',
},
});
devServer = await fixture.startDevServer();
});
after(async () => {
await devServer.stop();
describe('dev', () => {
/** @type {import('./test-utils').DevServer} */
let devServer;
before(async () => {
devServer = await fixture.startDevServer();
});
after(async () => {
await devServer.stop();
});
it('Does not crash the dev server', async () => {
let res = await fixture.fetch('/');
let html = await res.text();
assert.equal(html.includes('ReferenceError'), true);
res = await fixture.fetch('/');
await res.text();
assert.equal(html.includes('ReferenceError'), true);
});
});
it('Does not crash the dev server', async () => {
let res = await fixture.fetch('/');
let html = await res.text();
describe('build', () => {
before(async () => {
await fixture.build();
});
assert.equal(html.includes('ReferenceError'), true);
it('in nested components, does not crash server', async () => {
const app = await fixture.loadTestAdapterApp();
const request = new Request('http://example.com/in-stream');
const response = await app.render(request);
res = await fixture.fetch('/');
await res.text();
assert.equal(html.includes('ReferenceError'), true);
try {
await response.text();
assert.ok(false, 'error expected');
} catch {
assert.ok(true, "error caught during render");
}
});
});
});

View file

@ -0,0 +1,6 @@
---
import other from '../other.js';
---
<div>
{other()}
</div>

View file

@ -0,0 +1,4 @@
export default function() {
return somethingNotExists();
}

View file

@ -0,0 +1,17 @@
---
import Other from '../components/Other.astro';
---
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<title>Astro</title>
</head>
<body>
<h1>Astro</h1>
<Other />
</body>
</html>

View file

@ -1 +1,3 @@
export var foo = bar;
export default foo;