mirror of
https://github.com/withastro/astro.git
synced 2024-12-16 21:46:22 -05:00
fix(app): provide adapter locals to error pages (#10427)
This commit is contained in:
parent
c70aa6849f
commit
128c7a3639
6 changed files with 48 additions and 5 deletions
5
.changeset/thin-deers-sin.md
Normal file
5
.changeset/thin-deers-sin.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
"astro": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fixes an issue where error pages did not have access to the `Astro.locals` fields provided by the adapter.
|
|
@ -66,6 +66,7 @@ export interface RenderOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RenderErrorOptions {
|
export interface RenderErrorOptions {
|
||||||
|
locals?: App.Locals,
|
||||||
routeData?: RouteData;
|
routeData?: RouteData;
|
||||||
response?: Response;
|
response?: Response;
|
||||||
status: 404 | 500;
|
status: 404 | 500;
|
||||||
|
@ -295,7 +296,7 @@ export class App {
|
||||||
routeData = this.match(request);
|
routeData = this.match(request);
|
||||||
}
|
}
|
||||||
if (!routeData) {
|
if (!routeData) {
|
||||||
return this.#renderError(request, { status: 404 });
|
return this.#renderError(request, { locals, status: 404 });
|
||||||
}
|
}
|
||||||
const pathname = this.#getPathnameFromRequest(request);
|
const pathname = this.#getPathnameFromRequest(request);
|
||||||
const defaultStatus = this.#getDefaultStatusCode(routeData, pathname);
|
const defaultStatus = this.#getDefaultStatusCode(routeData, pathname);
|
||||||
|
@ -314,7 +315,7 @@ export class App {
|
||||||
response = await renderContext.render(await mod.page());
|
response = await renderContext.render(await mod.page());
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
this.#logger.error(null, err.stack || err.message || String(err));
|
this.#logger.error(null, err.stack || err.message || String(err));
|
||||||
return this.#renderError(request, { status: 500 });
|
return this.#renderError(request, { locals, status: 500 });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
@ -322,6 +323,7 @@ export class App {
|
||||||
response.headers.get(REROUTE_DIRECTIVE_HEADER) !== 'no'
|
response.headers.get(REROUTE_DIRECTIVE_HEADER) !== 'no'
|
||||||
) {
|
) {
|
||||||
return this.#renderError(request, {
|
return this.#renderError(request, {
|
||||||
|
locals,
|
||||||
response,
|
response,
|
||||||
status: response.status as 404 | 500,
|
status: response.status as 404 | 500,
|
||||||
});
|
});
|
||||||
|
@ -374,7 +376,7 @@ export class App {
|
||||||
*/
|
*/
|
||||||
async #renderError(
|
async #renderError(
|
||||||
request: Request,
|
request: Request,
|
||||||
{ status, response: originalResponse, skipMiddleware = false }: RenderErrorOptions
|
{ locals, status, response: originalResponse, skipMiddleware = false }: RenderErrorOptions
|
||||||
): Promise<Response> {
|
): Promise<Response> {
|
||||||
const errorRoutePath = `/${status}${this.#manifest.trailingSlash === 'always' ? '/' : ''}`;
|
const errorRoutePath = `/${status}${this.#manifest.trailingSlash === 'always' ? '/' : ''}`;
|
||||||
const errorRouteData = matchRoute(errorRoutePath, this.#manifestData);
|
const errorRouteData = matchRoute(errorRoutePath, this.#manifestData);
|
||||||
|
@ -397,6 +399,7 @@ export class App {
|
||||||
const mod = await this.#getModuleForRoute(errorRouteData);
|
const mod = await this.#getModuleForRoute(errorRouteData);
|
||||||
try {
|
try {
|
||||||
const renderContext = RenderContext.create({
|
const renderContext = RenderContext.create({
|
||||||
|
locals,
|
||||||
pipeline: this.#pipeline,
|
pipeline: this.#pipeline,
|
||||||
middleware: skipMiddleware ? (_, next) => next() : undefined,
|
middleware: skipMiddleware ? (_, next) => next() : undefined,
|
||||||
pathname: this.#getPathnameFromRequest(request),
|
pathname: this.#getPathnameFromRequest(request),
|
||||||
|
@ -410,6 +413,7 @@ export class App {
|
||||||
// Middleware may be the cause of the error, so we try rendering 404/500.astro without it.
|
// Middleware may be the cause of the error, so we try rendering 404/500.astro without it.
|
||||||
if (skipMiddleware === false) {
|
if (skipMiddleware === false) {
|
||||||
return this.#renderError(request, {
|
return this.#renderError(request, {
|
||||||
|
locals,
|
||||||
status,
|
status,
|
||||||
response: originalResponse,
|
response: originalResponse,
|
||||||
skipMiddleware: true,
|
skipMiddleware: true,
|
||||||
|
|
4
packages/astro/test/fixtures/ssr-locals/src/pages/404.astro
vendored
Normal file
4
packages/astro/test/fixtures/ssr-locals/src/pages/404.astro
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
const { foo } = Astro.locals;
|
||||||
|
---
|
||||||
|
<h1 id="foo">{ foo }</h1>
|
4
packages/astro/test/fixtures/ssr-locals/src/pages/500.astro
vendored
Normal file
4
packages/astro/test/fixtures/ssr-locals/src/pages/500.astro
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
const { foo } = Astro.locals;
|
||||||
|
---
|
||||||
|
<h1 id="foo">{ foo }</h1>
|
3
packages/astro/test/fixtures/ssr-locals/src/pages/go-to-error-page.astro
vendored
Normal file
3
packages/astro/test/fixtures/ssr-locals/src/pages/go-to-error-page.astro
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
throw new Error
|
||||||
|
---
|
|
@ -7,6 +7,8 @@ import { loadFixture } from './test-utils.js';
|
||||||
describe('SSR Astro.locals from server', () => {
|
describe('SSR Astro.locals from server', () => {
|
||||||
/** @type {import('./test-utils').Fixture} */
|
/** @type {import('./test-utils').Fixture} */
|
||||||
let fixture;
|
let fixture;
|
||||||
|
/** @type {import('./test-utils.js').App} */
|
||||||
|
let app;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
|
@ -15,10 +17,10 @@ describe('SSR Astro.locals from server', () => {
|
||||||
adapter: testAdapter(),
|
adapter: testAdapter(),
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
|
app = await fixture.loadTestAdapterApp();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Can access Astro.locals in page', async () => {
|
it('Can access Astro.locals in page', async () => {
|
||||||
const app = await fixture.loadTestAdapterApp();
|
|
||||||
const request = new Request('http://example.com/foo');
|
const request = new Request('http://example.com/foo');
|
||||||
const locals = { foo: 'bar' };
|
const locals = { foo: 'bar' };
|
||||||
const response = await app.render(request, { locals });
|
const response = await app.render(request, { locals });
|
||||||
|
@ -29,7 +31,6 @@ describe('SSR Astro.locals from server', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Can access Astro.locals in api context', async () => {
|
it('Can access Astro.locals in api context', async () => {
|
||||||
const app = await fixture.loadTestAdapterApp();
|
|
||||||
const request = new Request('http://example.com/api');
|
const request = new Request('http://example.com/api');
|
||||||
const locals = { foo: 'bar' };
|
const locals = { foo: 'bar' };
|
||||||
const response = await app.render(request, undefined, locals);
|
const response = await app.render(request, undefined, locals);
|
||||||
|
@ -38,4 +39,26 @@ describe('SSR Astro.locals from server', () => {
|
||||||
|
|
||||||
assert.equal(body.foo, 'bar');
|
assert.equal(body.foo, 'bar');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('404.astro can access locals provided to app.render()', async () => {
|
||||||
|
const request = new Request('http://example.com/slkfnasf');
|
||||||
|
const locals = { foo: 'par' };
|
||||||
|
const response = await app.render(request, { locals });
|
||||||
|
assert.equal(response.status, 404);
|
||||||
|
|
||||||
|
const html = await response.text();
|
||||||
|
const $ = cheerio.load(html);
|
||||||
|
assert.equal($('#foo').text(), 'par');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('500.astro can access locals provided to app.render()', async () => {
|
||||||
|
const request = new Request('http://example.com/go-to-error-page');
|
||||||
|
const locals = { foo: 'par' };
|
||||||
|
const response = await app.render(request, { locals });
|
||||||
|
assert.equal(response.status, 500);
|
||||||
|
|
||||||
|
const html = await response.text();
|
||||||
|
const $ = cheerio.load(html);
|
||||||
|
assert.equal($('#foo').text(), 'par');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue