Skip to content

fix(site): restore SPA path before router boots so 404 page renders#15

Merged
DevelopmentCats merged 2 commits into
mainfrom
cat/site-404-fix
Jun 25, 2026
Merged

fix(site): restore SPA path before router boots so 404 page renders#15
DevelopmentCats merged 2 commits into
mainfrom
cat/site-404-fix

Conversation

@DevelopmentCats

Copy link
Copy Markdown
Collaborator

Changes

  • Move the GitHub Pages deep-link restoration step from site/src/main.tsx into an inline <script> in site/index.html's <head>.
  • Trim main.tsx to a short note pointing at the new location.
  • Polish NotFoundPage: show the attempted path in mono, add Raw JSON and Source links, scale up the visual hierarchy to match the other pages.
  • Update the comment in public/404.html to reference index.html instead of main.tsx.

Why this was needed

Going to scanner.registry.coder.com/anything-that-isn't-a-route was silently landing on the home page instead of NotFoundPage. The catch-all route already existed; it just never got hit.

The flow on GitHub Pages is:

  1. Pages serves public/404.html (HTTP 404).
  2. 404.html redirects to /?p=%2Fanything-that-isn't-a-route so the SPA gets a chance to render.
  3. The browser loads index.html, which has <script type="module" src="/src/main.tsx">.
  4. Module scripts are deferred. main.tsx imports ./App./router, which calls createBrowserRouter(...) at module load. At that moment window.location.pathname is still /, so the router locks in the home route.
  5. The old restoration block ran after those imports, so history.replaceState updated the URL bar to /anything-that-isn't-a-route but the router had already committed to /.

Moving the restoration into a synchronous inline script in <head> makes it run before the deferred module bundle, so the router sees the original path and the * catch-all renders NotFoundPage as intended.


This PR was prepared with help from Coder Agents.

Move the GitHub Pages deep-link restoration step from main.tsx into an
inline <script> in index.html's <head>. Module scripts are deferred, so
the old restore ran after createBrowserRouter had already captured the
post-bounce '/?p=...' URL and matched it to the home route. The inline
script runs synchronously before the bundle, so the router boots with
the original path and the catch-all NotFoundPage renders.

Also polish NotFoundPage: show the attempted path, add Raw JSON and
Source links, larger visual hierarchy that matches the rest of the site.
@DevelopmentCats DevelopmentCats requested a review from bpmct as a code owner June 25, 2026 19:54
Copilot AI review requested due to automatic review settings June 25, 2026 19:54

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes GitHub Pages deep-link handling for the report SPA by restoring the original path before React Router initializes, ensuring unknown routes correctly render NotFoundPage instead of silently landing on the home page.

Changes:

  • Moved the ?p=... deep-link restoration logic from site/src/main.tsx to an inline <script> in site/index.html’s <head>.
  • Updated public/404.html documentation comment to reference the new restore location.
  • Refreshed NotFoundPage UI and added links to Raw JSON and source.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
site/src/pages/NotFoundPage.tsx Improves 404 UX, shows attempted path, adds navigation and resource links.
site/src/main.tsx Removes late path-restore logic and leaves a note pointing to index.html.
site/public/404.html Updates fallback comment to reference the new restore step location.
site/index.html Adds an inline head script to restore deep-linked paths before the router boots.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread site/index.html
Build the restored URL by feeding `p` into the URL constructor and
appending any extra search params from the bounce URL. The old version
concatenated strings, which produced a malformed `/foo?a=1?x=2` if `p`
already carried a query (or an extra param landed on the bounce URL).

Also reject `p` values that don't look like same-origin relative paths
so a crafted `?p=//host/foo` can't try to flip the visible origin.

Addresses Copilot feedback on #15.
@DevelopmentCats DevelopmentCats merged commit 70a9efc into main Jun 25, 2026
5 checks passed
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