Skip to content

Commit

Permalink
Allow components to return a Response (#2944)
Browse files Browse the repository at this point in the history
* Allow components to return a Response

* Changeset
  • Loading branch information
matthewp authored Mar 30, 2022
1 parent d7ece97 commit c989f10
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 15 deletions.
5 changes: 5 additions & 0 deletions .changeset/chatty-cows-attack.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Allow components to return a Response
42 changes: 27 additions & 15 deletions packages/astro/src/runtime/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,8 @@ async function replaceHeadInjection(result: SSRResult, html: string): Promise<st
export async function renderToString(result: SSRResult, componentFactory: AstroComponentFactory, props: any, children: any): Promise<string> {
const Component = await componentFactory(result, props, children);
if (!isAstroComponent(Component)) {
throw new Error('Cannot return a Response from a nested component.');
const response: Response = Component;
throw response;
}

let template = await renderAstroComponent(Component);
Expand All @@ -425,20 +426,31 @@ export async function renderPage(
props: any,
children: any
): Promise<{ type: 'html'; html: string } | { type: 'response'; response: Response }> {
const response = await componentFactory(result, props, children);

if (isAstroComponent(response)) {
let template = await renderAstroComponent(response);
const html = await replaceHeadInjection(result, template);
return {
type: 'html',
html,
};
} else {
return {
type: 'response',
response,
};
try {
const response = await componentFactory(result, props, children);

if (isAstroComponent(response)) {
let template = await renderAstroComponent(response);
const html = await replaceHeadInjection(result, template);
return {
type: 'html',
html,
};
} else {
return {
type: 'response',
response,
};
}
} catch(err) {
if(err instanceof Response) {
return {
type: 'response',
response: err
};
} else {
throw err;
}
}
}

Expand Down
32 changes: 32 additions & 0 deletions packages/astro/test/astro-response.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { expect } from 'chai';
import { load as cheerioLoad } from 'cheerio';
import { loadFixture } from './test-utils.js';

// Asset bundling
describe('Returning responses', () => {
let fixture;
/** @type {import('./test-utils').DevServer} */
let devServer;

before(async () => {
fixture = await loadFixture({
projectRoot: './fixtures/astro-response/',
});

devServer = await fixture.startDevServer();
});

after(async () => {
await devServer.stop();
});

it('Works from a page', async () => {
let response = await fixture.fetch('/not-found');
expect(response.status).to.equal(404);
});

it('Works from a component', async () => {
let response = await fixture.fetch('/not-found-component');
expect(response.status).to.equal(404);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
return new Response(null, {
status: 404,
statusText: `Not found`
});
---
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
import NotFound from '../components/not-found.astro';
---
<NotFound />
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
return new Response(null, {
status: 404,
statusText: `Not found`
});
---

0 comments on commit c989f10

Please sign in to comment.