Legacy Redirects

The Cloudflare Worker runs checkLegacyRedirect() from src/utils/redirects.ts before Vike SSR. Any match produces a 301 and the page never renders. This page documents the map, the invariant the test suite enforces, and how to extend it safely.

Where it runs

src/worker.ts calls checkLegacyRedirect(url.pathname) early in the request pipeline (after asset and trailing-slash handling, before SSR). If it returns a string, the Worker responds with 301 Location: <target>. If it returns null, the request continues to Vike.

The redirect step also re-runs on Vike 404s, so a page that doesn't exist gets a second chance to redirect before showing the 404 UI.

Two layers

redirects.ts exports two pieces, both consulted by checkLegacyRedirect():

  1. LEGACY_URL_MAPPINGS — a flat Record<string, string> of one-to-one redirects. Used for known WordPress URLs that need a single fixed target. Compiled into a regex from the keys at module load time, so a match is unconditional (no 404 check).
  2. REDIRECT_PATTERNS — an ordered array of RedirectPattern rules for shape-based rewrites (AMP cleanup, paginated author URLs, blog category remaps, etc.). Each rule may set checkOnly404: true to opt into "only run if Vike would 404 anyway."

Order matters: LEGACY_URL_MAPPINGS is REDIRECT_PATTERNS[0], so static entries always win over broader pattern rules.

Invariant: no live-route collisions

Because matches are unconditional, a key in LEGACY_URL_MAPPINGS that also names a live page silently hides that page. This has happened in the past — a GSC "Not found (404)" cleanup added URLs as redirects, and a later sprint resurrected the same pages without removing the entries.

The invariant is now enforced by tests/unit/utils/redirects.liveCollision.test.ts:

For every static EN route discovered from pages/**/+Page.tsx and every ES route from src/locales/routes.json, the default-mode call checkLegacyRedirect(route) must return null.

The test runs on npm run test:unit. It covers LEGACY_URL_MAPPINGS and any pattern that does not set checkOnly404. 404-only patterns are intentionally not asserted: by design they catch missing children of a section (e.g. /case-studies/<missing-slug>//case-studies/), and those patterns will match valid children too — they just never fire in practice because Vike renders the real page.

How to add a redirect safely

When adding entries to LEGACY_URL_MAPPINGS:

  1. Confirm the source URL is not a live page — search pages/**/+Page.tsx and src/locales/routes.json. The guard test does this automatically, so you can also rely on it failing CI.
  2. Confirm the target is a current canonical URL (not another legacy path that might itself disappear). The static map does not chase chains.
  3. Group the entry near a comment that explains the source (GSC report, inventory cleanup, etc.). Reference the originating ClickUp task so the next contributor can reconstruct the decision.

When adding a REDIRECT_PATTERNS rule, default to checkOnly404: true unless the source pattern is provably unreachable (spam, malformed AMP, etc.). 404-gated rules can't shadow a future live page.

Removing an entry

If a page that was redirected away comes back as a live route, remove its LEGACY_URL_MAPPINGS entry in the same PR that ships the page. The guard test will fail otherwise.

  • swapps-client/src/utils/redirects.ts — the map, patterns, and checkLegacyRedirect().
  • swapps-client/src/worker.ts — where it is invoked.
  • swapps-client/tests/unit/utils/redirects.test.ts — behavior tests.
  • swapps-client/tests/unit/utils/redirects.liveCollision.test.ts — the live-route guard.