Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/cloudflare-prerender-routing-mismatch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Fixes non-prerendered routes failing when a dynamic prerendered route exists in the same project with `prerenderEnvironment: 'node'`
21 changes: 20 additions & 1 deletion packages/astro/src/vite-plugin-app/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@ export class AstroServerApp extends BaseApp<RunnablePipeline> {
incomingRequest,
incomingResponse,
isHttps,
}: HandleRequest): Promise<void> {
prerenderOnly,
}: HandleRequest): Promise<boolean> {
// When the dev server runs behind a TLS-terminating reverse proxy (e.g.
// Caddy, nginx, Traefik), the proxy connects to Vite over plain HTTP while
// the browser communicates over HTTPS. In that setup isHttps is false, but
Expand Down Expand Up @@ -199,16 +200,31 @@ export class AstroServerApp extends BaseApp<RunnablePipeline> {

const self = this;
await self.#loadFetchHandler();

let handled = true;
await runWithErrorHandling({
controller,
pathname,
async run() {
const matchedRoute = await self.devMatch(pathname);
if (!matchedRoute) {
if (prerenderOnly) {
// In prerender-only mode, signal that we didn't handle this
// so the caller can fall through to the SSR handler.
handled = false;
return;
}
// This should never happen, because ensure404Route will add a 404 route if none exists.
throw new Error('No route matched, and default 404 route was not found.');
}

// When running as the prerender handler, only handle prerendered routes.
// If the best-matching route is SSR, let the SSR handler handle it instead.
if (prerenderOnly && !matchedRoute.routeData.prerender) {
handled = false;
return;
}

const request = createRequest({
url,
headers: incomingRequest.headers,
Expand Down Expand Up @@ -250,6 +266,7 @@ export class AstroServerApp extends BaseApp<RunnablePipeline> {
return error;
},
});
return handled;
}

match(request: Request, _allowPrerenderedRoutes: boolean): RouteData | undefined {
Expand Down Expand Up @@ -282,4 +299,6 @@ type HandleRequest = {
incomingRequest: http.IncomingMessage;
incomingResponse: http.ServerResponse;
isHttps: boolean;
/** When true, only handle prerendered routes. Returns false for SSR routes. */
prerenderOnly?: boolean;
};
9 changes: 7 additions & 2 deletions packages/astro/src/vite-plugin-app/createAstroServerApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,17 @@ export default async function createAstroServerApp(
}

return {
handler(incomingRequest: http.IncomingMessage, incomingResponse: http.ServerResponse) {
app.handleRequest({
handler(
incomingRequest: http.IncomingMessage,
incomingResponse: http.ServerResponse,
options?: { prerenderOnly?: boolean },
) {
return app.handleRequest({
controller,
incomingRequest,
incomingResponse,
isHttps: loader?.isHttps() ?? false,
prerenderOnly: options?.prerenderOnly,
});
},
};
Expand Down
13 changes: 11 additions & 2 deletions packages/astro/src/vite-plugin-astro-server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,18 @@ export default function createVitePluginAstroServer({
return next();
}

localStorage.run(request, () => {
prerenderHandler.handler(request, response);
const handled = await new Promise<boolean>((resolve) => {
localStorage.run(request, () => {
prerenderHandler
.handler(request, response, { prerenderOnly: true })
.then((result: boolean) => resolve(result))
.catch(() => resolve(true));
});
});

if (!handled) {
return next();
}
} catch (err) {
next(err);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
export const prerender = true;

export function getStaticPaths() {
return [
{ params: { page: 'one' } },
{ params: { page: 'two' } },
];
}

const { page } = Astro.params;
---

<html lang="en">
<head>
<meta charset="utf-8" />
<title>Page {page}</title>
</head>
<body>
<h1>Page {page}</h1>
<p id="page-name">{page}</p>
</body>
</html>
Loading