Skip to content

Commit

Permalink
Prevent errors in rendering from crashing server (#10221)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
matthewp and florian-lefebvre authored Feb 26, 2024
1 parent 84502b4 commit 4db82d9
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 14 deletions.
5 changes: 5 additions & 0 deletions .changeset/breezy-pears-admire.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"astro": patch
---

Prevents errors in templates from crashing the server
3 changes: 3 additions & 0 deletions packages/astro/src/runtime/server/render/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
55 changes: 41 additions & 14 deletions packages/astro/test/error-bad-js.test.js
Original file line number Diff line number Diff line change
@@ -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();
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);
});
});

assert.equal(html.includes('ReferenceError'), true);
describe('build', () => {
before(async () => {
await fixture.build();
});

res = await fixture.fetch('/');
await res.text();
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);

assert.equal(html.includes('ReferenceError'), true);
try {
await response.text();
assert.ok(false, 'error expected');
} catch {
assert.ok(true, "error caught during render");
}
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
import other from '../other.js';
---
<div>
{other()}
</div>
4 changes: 4 additions & 0 deletions packages/astro/test/fixtures/error-bad-js/src/other.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

export default function() {
return somethingNotExists();
}
Original file line number Diff line number Diff line change
@@ -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>
2 changes: 2 additions & 0 deletions packages/astro/test/fixtures/error-bad-js/src/something.js
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export var foo = bar;

export default foo;

0 comments on commit 4db82d9

Please sign in to comment.