Allow components to return a Response (#2944)

* Allow components to return a Response

* Changeset
This commit is contained in:
Matthew Phillips 2022-03-30 15:55:22 -04:00 committed by GitHub
parent d7ece97d20
commit c989f106f9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 79 additions and 14 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Allow components to return a Response

View file

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

View file

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

View file

@ -0,0 +1,6 @@
---
return new Response(null, {
status: 404,
statusText: `Not found`
});
---

View file

@ -0,0 +1,4 @@
---
import NotFound from '../components/not-found.astro';
---
<NotFound />

View file

@ -0,0 +1,6 @@
---
return new Response(null, {
status: 404,
statusText: `Not found`
});
---