Skip to content

fix: serve pages in SPA mode when the route also has an API handler - #2354

Merged
brenelz merged 1 commit into
mainfrom
fix/spa-page-with-api-handler
Oct 14, 2026
Merged

brenelz merged 1 commit into
mainfrom
fix/spa-page-with-api-handler

Conversation

@lxsmnsyc

Copy link
Copy Markdown
Member

Problem

With ssr: false, a route file that exports both a page and an API handler breaks page requests. For example:

// routes/[...404].tsx
export const GET = (event: APIEvent) => {
  if (event.request.headers.get("accept") !== "application/json") return;
  return { notFound: "API" };
};

export default function NotFound() { /* ... */ }

Every URL this route matches returns 404 instead of the SPA shell. A catch-all matches every page without its own API route, so the whole app is a 404. The experiments fixture has this route.

Cause

matchAPIRoute counted a route as a page only when it had a page component:

const isPage = route.page === true && route.$component !== undefined;

SPA builds leave page components out of the server routes (dataOnly in the server file router), so isPage was always false there. When the GET returned undefined, the handler hit if (!match.isPage) return; and h3 answered 404.

Fix

Use route.page alone. With SSR, a route with a page always has its component, so SSR doesn't change.

Verification

basic fixture with export const GET = () => undefined added to [...404].tsx, production builds:

Mode / /about /nope
ssr: false, before 404 404 404
ssr: false, after 200 200 200 (the client renders the not-found page)
SSR, after 200 200 404 (unchanged)
  • New server/routes.spec.ts. The SPA case fails without the fix.
  • packages/start: 243 tests, typecheck, format check.
  • apps/tests: unit plus Playwright (42, 42, 3).

I found this while working on #2352. That PR also fixes the SPA server entry's missing getServerFunctionMeta export, which kept the experiments fixture from building with ssr: false at all.

🤖 Generated with Claude Code

`matchAPIRoute` only counted a route as a page when it had a page
component. SPA builds leave page components out of the server routes, so a
route file exporting both a page and `GET` was treated as API-only. When
its `GET` returned nothing, the handler stopped there and h3 answered 404.
A catch-all like `[...404].tsx` with a `GET` turned every page into a 404.

Use `route.page` alone. SSR routes with a page always have the component,
so nothing changes there.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Oct 14, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 45e83b5

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@solidjs/start Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@netlify

netlify Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for solid-start-landing-page ready!

Name Link
🔨 Latest commit 45e83b5
🔍 Latest deploy log https://app.netlify.com/projects/solid-start-landing-page/deploys/6acf13f18d0d3e0e8f8b2498
😎 Deploy Preview https://deploy-preview-2354--solid-start-landing-page.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@pkg-pr-new

pkg-pr-new Bot commented Oct 14, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@solidjs/start@2354

commit: 45e83b5

@brenelz
brenelz merged commit eb50f39 into main Oct 14, 2026
13 checks passed
@brenelz
brenelz deleted the fix/spa-page-with-api-handler branch October 14, 2026 13:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants