Repository navigation
Platform SSR correctness: route rules, emitted entries, and navigation errors #2522
Description
Please provide the environment you discovered this bug in.
- Analog
3.0.0-alpha.86, untouched upstreamalphaat4225f45090a4cf4bdfb562a788e908787b6ec73c. - Linux, Node
24.15.0, pnpm10.33.0, Angular22.0.0, Vite8.0.8, Nitro3.0.260903-beta. - Reproduction uses the repository's existing application and Playwright test; no private consumer is needed.
git clone --branch alpha https://github.com/analogjs/analog.git analog-ssr-repro
cd analog-ssr-repro
git checkout 4225f45090a4cf4bdfb562a788e908787b6ec73c
pnpm install --frozen-lockfile
pnpm exec playwright install chromium
CI=true NX_DAEMON=false NX_NO_CLOUD=true pnpm exec nx e2e analog-app-e2e --grep="only injects JSON-LD client-side" --skipNxCacheUse Node 24.15.0 for the reproduction. The test target builds and starts its own local server.
Which area/package is the issue in?
platform, with the router's buffered-render error handoff relevant to the later error-handling portion.
Description
This tracks the platform SSR workstream requested in Brandon's review of analogjs/analog#2516: route policies, emitted SSR entry discovery, and buffered error behavior.
The first independently reproduced blocker is a route with ssr: false still being server-rendered:
nitro({
routeRules: {
'/client': { ssr: false },
'/admin/**': { ssr: false },
'/admin/help': { ssr: true },
},
});The /client response should contain the client application shell, with its component and JSON-LD added only after client bootstrap. Instead, the raw HTTP response already contains <analog-client> and the rendered page content. The unchanged apps/analog-app-e2e/tests/json-ld.spec.ts assertion fails on untouched alpha.
The renderer currently reads the no-SSR hint from response headers before Nitro's response-header middleware applies it. The matched rule is already available on the event context. In addition, an explicit child ssr: true needs to reset an inherited opt-out instead of retaining the parent's hint.
This also blocks the otherwise focused compiler PR analogjs/analog#2520 in the shared E2E job. The route-policy repair is isolated in analogjs/analog#2523, which is green and ready for review. Entry discovery, buffered errors, and Worker output corrections are published in analogjs/analog#2528. Compiler functionality remains in its dedicated PR.
The follow-up's regression commit records missing/ambiguous entry failures and actual failed resolvers returning HTTP 200. The same package and built-server assertions pass after repair, including safe 404/503/500 documents and concurrent successful requests.
Worker qualification also found the Pages output layout being imposed on Module Workers, placing server code inside their asset directory. A synthetic local Miniflare reproduction served a server chunk with bytes identical to the server file. The scoped output fix preserves Nitro's separate Module/Durable server and asset directories while retaining Pages behavior. Its package gates and the later packed local Workerd qualification pass. Deployment scripts that referenced the accidental Module _worker.js layout should use the generated Wrangler configuration.
Please provide the exception or error you saw
JSON-LD > only injects JSON-LD client-side for no-SSR routes
expect(rawHtml).not.toContain('analog-client')
Received: server-rendered HTML containing <analog-client>
The failure reproduces before any implementation changes in a separate baseline worktree. It is not an intermittent browser timing assertion: it inspects the raw server response.
Other information
Workstream acceptance criteria:
- Route policies apply before rendering; an explicit child opt-in resets inherited opt-out.
- The existing built-app no-SSR/JSON-LD E2E assertion passes unchanged, with focused generated-renderer tests for precedence and normal rendering.
- Emitted
.js/.mjsentries are discovered deterministically; missing or ambiguous output fails at build time. - Buffered SSR navigation failures preserve valid error statuses and return safe, non-cacheable HTML without exception details or application bootstrap scripts.
- Worker bundling honors the target policy, and Module/Durable server output remains outside the asset directory.
- Every PR includes its own reproducible tests and documentation. The route-policy PR does not close the remaining criteria.
Both focused PRs target alpha and pass CI: analogjs/analog#2523 at 535fb080ee9b29931a6f6232a08f532213f164f0, and analogjs/analog#2528 at 01ae947367216b3dbcea314111cb8d5d5a36ab03. The route-policy PR also restores caller-supplied x-analog-no-ssr filtering with request-adapter and built HTTP tests: callers cannot disable an SSR-enabled route or enable a configured client-rendered route. The entry/error PR includes deterministic output discovery, safe status/error handling, complete prerendered HTML/sitemap checks, and Worker output separation. The earlier regression commits above remain historical reproductions. This issue stays open until both contributions are merged.
I would be willing to submit a PR to fix this issue
- Yes
Prepared with OpenAI Codex; the route-policy defect was reproduced on untouched alpha.
Activity