can jump 404 when that page does not exist (#5701)
This commit is contained in:
parent
21a55b3276
commit
9869f2f6d8
11 changed files with 99 additions and 9 deletions
5
.changeset/red-snakes-fetch.md
Normal file
5
.changeset/red-snakes-fetch.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@astrojs/node': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Support custom 404 page in standalone mode
|
|
@ -41,6 +41,7 @@
|
||||||
"astro": "workspace:*",
|
"astro": "workspace:*",
|
||||||
"astro-scripts": "workspace:*",
|
"astro-scripts": "workspace:*",
|
||||||
"chai": "^4.3.6",
|
"chai": "^4.3.6",
|
||||||
|
"cheerio": "^1.0.0-rc.11",
|
||||||
"mocha": "^9.2.2",
|
"mocha": "^9.2.2",
|
||||||
"node-mocks-http": "^1.11.0",
|
"node-mocks-http": "^1.11.0",
|
||||||
"undici": "^5.14.0"
|
"undici": "^5.14.0"
|
||||||
|
|
|
@ -2,16 +2,17 @@ import type { NodeApp } from 'astro/app/node';
|
||||||
import type { IncomingMessage, ServerResponse } from 'http';
|
import type { IncomingMessage, ServerResponse } from 'http';
|
||||||
import type { Readable } from 'stream';
|
import type { Readable } from 'stream';
|
||||||
import { responseIterator } from './response-iterator';
|
import { responseIterator } from './response-iterator';
|
||||||
|
import type { Options } from './types';
|
||||||
|
|
||||||
export default function (app: NodeApp) {
|
export default function (app: NodeApp, mode: Options['mode']) {
|
||||||
return async function (
|
return async function (
|
||||||
req: IncomingMessage,
|
req: IncomingMessage,
|
||||||
res: ServerResponse,
|
res: ServerResponse,
|
||||||
next?: (err?: unknown) => void
|
next?: (err?: unknown) => void
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
const route = app.match(req);
|
const route =
|
||||||
|
mode === 'standalone' ? app.match(req, { matchNotFound: true }) : app.match(req);
|
||||||
if (route) {
|
if (route) {
|
||||||
try {
|
try {
|
||||||
const response = await app.render(req);
|
const response = await app.render(req);
|
||||||
|
|
|
@ -9,10 +9,10 @@ polyfill(globalThis, {
|
||||||
exclude: 'window document',
|
exclude: 'window document',
|
||||||
});
|
});
|
||||||
|
|
||||||
export function createExports(manifest: SSRManifest) {
|
export function createExports(manifest: SSRManifest, options: Options) {
|
||||||
const app = new NodeApp(manifest);
|
const app = new NodeApp(manifest);
|
||||||
return {
|
return {
|
||||||
handler: middleware(app),
|
handler: middleware(app, options.mode),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ export function getResolvedHostForHttpServer(host: string | boolean) {
|
||||||
export default function startServer(app: NodeApp, options: Options) {
|
export default function startServer(app: NodeApp, options: Options) {
|
||||||
const port = process.env.PORT ? Number(process.env.PORT) : options.port ?? 8080;
|
const port = process.env.PORT ? Number(process.env.PORT) : options.port ?? 8080;
|
||||||
const { client } = resolvePaths(options);
|
const { client } = resolvePaths(options);
|
||||||
const handler = middleware(app);
|
const handler = middleware(app, options.mode);
|
||||||
|
|
||||||
// Allow to provide host value at runtime
|
// Allow to provide host value at runtime
|
||||||
const host = getResolvedHostForHttpServer(
|
const host = getResolvedHostForHttpServer(
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import nodejs from '../dist/index.js';
|
import nodejs from '../dist/index.js';
|
||||||
import { loadFixture, createRequestAndResponse, toPromise } from './test-utils.js';
|
import { loadFixture, createRequestAndResponse } from './test-utils.js';
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
|
|
||||||
describe('API routes', () => {
|
describe('API routes', () => {
|
||||||
|
@ -17,18 +17,21 @@ describe('API routes', () => {
|
||||||
|
|
||||||
it('Can get the request body', async () => {
|
it('Can get the request body', async () => {
|
||||||
const { handler } = await import('./fixtures/api-route/dist/server/entry.mjs');
|
const { handler } = await import('./fixtures/api-route/dist/server/entry.mjs');
|
||||||
|
|
||||||
let { req, res, done } = createRequestAndResponse({
|
let { req, res, done } = createRequestAndResponse({
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
url: '/recipes',
|
url: '/recipes',
|
||||||
});
|
});
|
||||||
|
|
||||||
handler(req, res);
|
handler(req, res);
|
||||||
req.send(JSON.stringify({ id: 2 }));
|
|
||||||
|
|
||||||
|
req.send(JSON.stringify({ id: 2 }));
|
||||||
|
|
||||||
let [buffer] = await done;
|
let [buffer] = await done;
|
||||||
|
|
||||||
let json = JSON.parse(buffer.toString('utf-8'));
|
let json = JSON.parse(buffer.toString('utf-8'));
|
||||||
|
|
||||||
expect(json.length).to.equal(1);
|
expect(json.length).to.equal(1);
|
||||||
|
|
||||||
expect(json[0].name).to.equal('Broccoli Soup');
|
expect(json[0].name).to.equal('Broccoli Soup');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
9
packages/integrations/node/test/fixtures/node-middleware/package.json
vendored
Normal file
9
packages/integrations/node/test/fixtures/node-middleware/package.json
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"name": "@test/node-middleware",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"astro": "workspace:*",
|
||||||
|
"@astrojs/node": "workspace:*"
|
||||||
|
}
|
||||||
|
}
|
13
packages/integrations/node/test/fixtures/node-middleware/src/pages/404.astro
vendored
Normal file
13
packages/integrations/node/test/fixtures/node-middleware/src/pages/404.astro
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
---
|
||||||
|
---
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>404</title>
|
||||||
|
</head>
|
||||||
|
<body><h1>404!!!!!!!!!!</h1></body>
|
||||||
|
</html>
|
11
packages/integrations/node/test/fixtures/node-middleware/src/pages/index.astro
vendored
Normal file
11
packages/integrations/node/test/fixtures/node-middleware/src/pages/index.astro
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
---
|
||||||
|
|
||||||
|
<html lang="en">
|
||||||
|
<head><title>node-middleware</title></head>
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
|
<body>
|
||||||
|
<div>1</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
37
packages/integrations/node/test/node-middleware.test.js
Normal file
37
packages/integrations/node/test/node-middleware.test.js
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import nodejs from '../dist/index.js';
|
||||||
|
import { loadFixture , createRequestAndResponse} from './test-utils.js';
|
||||||
|
import { expect } from 'chai';
|
||||||
|
import * as cheerio from 'cheerio';
|
||||||
|
|
||||||
|
describe('test 404 cant load', () => {
|
||||||
|
let fixture;
|
||||||
|
before(async () => {
|
||||||
|
fixture = await loadFixture({
|
||||||
|
root: './fixtures/node-middleware/',
|
||||||
|
output: 'server',
|
||||||
|
adapter: nodejs({ mode: 'standalone' }),
|
||||||
|
});
|
||||||
|
await fixture.build();
|
||||||
|
});
|
||||||
|
describe('test 404', async () => {
|
||||||
|
let devPreview;
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
devPreview = await fixture.preview();
|
||||||
|
});
|
||||||
|
after(async () => {
|
||||||
|
await devPreview.stop();
|
||||||
|
});
|
||||||
|
it('when mode is standalone', async () => {
|
||||||
|
const res = await fixture.fetch('/error-page');
|
||||||
|
|
||||||
|
expect(res.status).to.equal(404);
|
||||||
|
|
||||||
|
const html = await res.text();
|
||||||
|
const $ = cheerio.load(html);
|
||||||
|
|
||||||
|
const h1 = $('h1');
|
||||||
|
expect(h1.text()).to.equal('404!!!!!!!!!!');
|
||||||
|
});
|
||||||
|
})
|
||||||
|
})
|
|
@ -3063,6 +3063,7 @@ importers:
|
||||||
astro: workspace:*
|
astro: workspace:*
|
||||||
astro-scripts: workspace:*
|
astro-scripts: workspace:*
|
||||||
chai: ^4.3.6
|
chai: ^4.3.6
|
||||||
|
cheerio: ^1.0.0-rc.11
|
||||||
mocha: ^9.2.2
|
mocha: ^9.2.2
|
||||||
node-mocks-http: ^1.11.0
|
node-mocks-http: ^1.11.0
|
||||||
send: ^0.18.0
|
send: ^0.18.0
|
||||||
|
@ -3075,6 +3076,7 @@ importers:
|
||||||
astro: link:../../astro
|
astro: link:../../astro
|
||||||
astro-scripts: link:../../../scripts
|
astro-scripts: link:../../../scripts
|
||||||
chai: 4.3.7
|
chai: 4.3.7
|
||||||
|
cheerio: 1.0.0-rc.12
|
||||||
mocha: 9.2.2
|
mocha: 9.2.2
|
||||||
node-mocks-http: 1.12.1
|
node-mocks-http: 1.12.1
|
||||||
undici: 5.14.0
|
undici: 5.14.0
|
||||||
|
@ -3087,6 +3089,14 @@ importers:
|
||||||
'@astrojs/node': link:../../..
|
'@astrojs/node': link:../../..
|
||||||
astro: link:../../../../../astro
|
astro: link:../../../../../astro
|
||||||
|
|
||||||
|
packages/integrations/node/test/fixtures/node-middleware:
|
||||||
|
specifiers:
|
||||||
|
'@astrojs/node': workspace:*
|
||||||
|
astro: workspace:*
|
||||||
|
dependencies:
|
||||||
|
'@astrojs/node': link:../../..
|
||||||
|
astro: link:../../../../../astro
|
||||||
|
|
||||||
packages/integrations/partytown:
|
packages/integrations/partytown:
|
||||||
specifiers:
|
specifiers:
|
||||||
'@builder.io/partytown': ^0.7.1
|
'@builder.io/partytown': ^0.7.1
|
||||||
|
|
Loading…
Reference in a new issue