Skip to content

Commit eb50f39

Browse files
lxsmnsycclaude
andauthored
fix: serve pages in SPA mode when the route also has an API handler (#2354)
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent e0e6f6d commit eb50f39

3 files changed

Lines changed: 42 additions & 2 deletions

File tree

‎.changeset/spa-page-api-route.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@solidjs/start": patch
3+
---
4+
5+
Serve pages in SPA mode (`ssr: false`) when a route file exports both a page and an API handler, such as a `[...404].tsx` with a `GET`. The server treated those routes as API-only, so a `GET` that returned nothing gave a 404 for every URL the route matched.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { describe, expect, it, vi } from "vitest";
2+
3+
const GET = { import: () => Promise.resolve({}) };
4+
5+
// What the server file router produces for `routes/[...404].tsx` exporting
6+
// both a page and `GET`, with and without the page component.
7+
vi.mock("solid-start:routes", () => ({
8+
default: [
9+
{
10+
path: "/*404",
11+
page: true,
12+
$component: { src: "routes/[...404].tsx", import: () => Promise.resolve({}) },
13+
$GET: GET,
14+
},
15+
{ path: "/spa/*404", page: true, $GET: GET },
16+
{ path: "/api/*rest", $GET: GET },
17+
],
18+
}));
19+
20+
const { matchAPIRoute } = await import("./routes.ts");
21+
22+
describe("matchAPIRoute", () => {
23+
it("marks a route with a page and an API handler as a page", () => {
24+
expect(matchAPIRoute("/missing", "GET")?.isPage).toBe(true);
25+
});
26+
27+
it("marks it as a page in SPA builds, where the server routes have no page components", () => {
28+
expect(matchAPIRoute("/spa/missing", "GET")?.isPage).toBe(true);
29+
});
30+
31+
it("does not mark an API-only route as a page", () => {
32+
expect(matchAPIRoute("/api/missing", "GET")?.isPage).toBe(false);
33+
});
34+
});

‎packages/start/src/server/routes.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,9 @@ export function matchAPIRoute(
111111

112112
if (handler === undefined) return;
113113

114-
// Check if this is a page route
115-
const isPage = route.page === true && route.$component !== undefined;
114+
// Check if this is a page route. SPA builds leave page components out of
115+
// the server routes, so this can't depend on `$component`.
116+
const isPage = route.page === true;
116117

117118
// Return comprehensive route information
118119
return {

0 commit comments

Comments
 (0)