Skip to content

Commit fb6850e

Browse files
committed
Include injected routes when determining whether renderers are needed in SSR builds
1 parent d0fe1ec commit fb6850e

5 files changed

Lines changed: 47 additions & 11 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'astro': patch
3+
---
4+
5+
Fixes SSR builds failing with "No matching renderer found" when a project only has injected routes and no `src/pages/` directory

packages/astro/src/actions/integration.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { AstroError } from '../core/errors/errors.js';
22
import { ActionsWithoutServerOutputError } from '../core/errors/errors-data.js';
3-
import { hasNonPrerenderedProjectRoute } from '../core/routing/helpers.js';
3+
import { hasNonPrerenderedRoute } from '../core/routing/helpers.js';
44
import { viteID } from '../core/util.js';
55
import type { AstroSettings } from '../types/astro.js';
66
import type { AstroIntegration } from '../types/public/integrations.js';
@@ -41,7 +41,7 @@ export default function astroIntegrationActionsRouteHandler({
4141
});
4242
},
4343
'astro:routes:resolved': ({ routes }) => {
44-
if (!hasNonPrerenderedProjectRoute(routes)) {
44+
if (!hasNonPrerenderedRoute(routes)) {
4545
const error = new AstroError(ActionsWithoutServerOutputError);
4646
error.stack = undefined;
4747
throw error;

packages/astro/src/core/routing/helpers.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -75,26 +75,28 @@ export function routeHasHtmlExtension(route: RouteData): boolean {
7575
);
7676
}
7777

78-
export function hasNonPrerenderedProjectRoute(
78+
export function hasNonPrerenderedRoute(
7979
routes: Array<Pick<RouteData, 'type' | 'origin' | 'prerender'>>,
80-
options?: { includeEndpoints?: boolean },
80+
options?: { includeEndpoints?: boolean; includeExternal?: boolean },
8181
): boolean;
82-
export function hasNonPrerenderedProjectRoute(
82+
export function hasNonPrerenderedRoute(
8383
routes: Array<Pick<IntegrationResolvedRoute, 'type' | 'origin' | 'isPrerendered'>>,
84-
options?: { includeEndpoints?: boolean },
84+
options?: { includeEndpoints?: boolean; includeExternal?: boolean },
8585
): boolean;
86-
export function hasNonPrerenderedProjectRoute(
86+
export function hasNonPrerenderedRoute(
8787
routes: Array<
8888
| Pick<RouteData, 'type' | 'origin' | 'prerender'>
8989
| Pick<IntegrationResolvedRoute, 'type' | 'origin' | 'isPrerendered'>
9090
>,
91-
options?: { includeEndpoints?: boolean },
91+
options?: { includeEndpoints?: boolean; includeExternal?: boolean },
9292
): boolean {
9393
const includeEndpoints = options?.includeEndpoints ?? true;
94+
const includeExternal = options?.includeExternal ?? false;
9495
const routeTypes: ReadonlyArray<string> = includeEndpoints ? ['page', 'endpoint'] : ['page'];
96+
const origins: ReadonlyArray<string> = includeExternal ? ['project', 'external'] : ['project'];
9597

9698
return routes.some((route) => {
9799
const isPrerendered = 'isPrerendered' in route ? route.isPrerendered : route.prerender;
98-
return routeTypes.includes(route.type) && route.origin === 'project' && !isPrerendered;
100+
return routeTypes.includes(route.type) && origins.includes(route.origin) && !isPrerendered;
99101
});
100102
}

packages/astro/src/vite-plugin-renderers/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { ConfigEnv, Plugin as VitePlugin } from 'vite';
22
import { ASTRO_VITE_ENVIRONMENT_NAMES } from '../core/constants.js';
3-
import { hasNonPrerenderedProjectRoute } from '../core/routing/helpers.js';
3+
import { hasNonPrerenderedRoute } from '../core/routing/helpers.js';
44
import type { ServerIslandsState } from '../core/server-islands/shared-state.js';
55
import type { AstroSettings, RoutesList } from '../types/astro.js';
66

@@ -40,8 +40,9 @@ export default function vitePluginRenderers(options: PluginOptions): VitePlugin
4040
this.environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.ssr &&
4141
renderers.length > 0 &&
4242
!options.serverIslandsState.hasIslands() &&
43-
!hasNonPrerenderedProjectRoute(options.routesList.routes, {
43+
!hasNonPrerenderedRoute(options.routesList.routes, {
4444
includeEndpoints: false,
45+
includeExternal: true,
4546
})
4647
) {
4748
return { code: `export const renderers = [];` };
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// @ts-check
2+
import assert from 'node:assert/strict';
3+
import { describe, it } from 'node:test';
4+
import { hasNonPrerenderedRoute } from '../../../dist/core/routing/helpers.js';
5+
6+
describe('hasNonPrerenderedRoute', () => {
7+
it('returns true when a non-prerendered project page exists', () => {
8+
const routes = [{ type: 'page', origin: 'project', prerender: false }];
9+
assert.equal(hasNonPrerenderedRoute(routes), true);
10+
});
11+
12+
it('returns false when all project pages are prerendered', () => {
13+
const routes = [{ type: 'page', origin: 'project', prerender: true }];
14+
assert.equal(hasNonPrerenderedRoute(routes), false);
15+
});
16+
17+
it('excludes endpoints when includeEndpoints is false', () => {
18+
const routes = [{ type: 'endpoint', origin: 'project', prerender: false }];
19+
assert.equal(hasNonPrerenderedRoute(routes, { includeEndpoints: false }), false);
20+
assert.equal(hasNonPrerenderedRoute(routes, { includeEndpoints: true }), true);
21+
});
22+
23+
it('returns true for injected (external) non-prerendered pages when includeExternal is true', () => {
24+
const routes = [{ type: 'page', origin: 'external', prerender: false }];
25+
assert.equal(hasNonPrerenderedRoute(routes, { includeExternal: true }), true);
26+
assert.equal(hasNonPrerenderedRoute(routes), false);
27+
});
28+
});

0 commit comments

Comments
 (0)