feat(routing): G E flip trailingSlash → always, cascade canonical URL form#16
Merged
Merged
Conversation
… form Eliminates the one-hop /ueber → /ueber/ 307 at the Cloudflare edge by making every URL we emit (canonical link, hreflang alternates, nav hrefs, breadcrumbs, i18n counterpart map, markdown editorial links) match the trailing-slash form Workers Static Assets serves natively. Astro config: trailingSlash 'never' → 'always'. canonicalise() in src/lib/i18n.ts inverts: keeps/adds trailing slash instead of stripping. counterparts map keys and values gain trailing slashes on both sides; the '/' ↔ '/en/' asymmetry is canonical, not a bug. getLocaleFromPath drops the now-dead '=== /en' first condition. Nav component href constants (SiteHeader homeHref/aboutHref/productsHref/contactHref; SiteFooter products/about/contact/legal/privacy) cascade with the *Active reducers simplified accordingly. EN-sibling breadcrumb anchors (/en, /en/products) and product-detail dynamic template-string hrefs on both index pages get the trailing slash. Two markdown editorial contact-page disclosures link to /datenschutz/ and /en/privacy/ for the same reason — the rendered HTML grep surfaced them. Verified locally: npm run check 0-error; npm run build clean; dist/- grep proves zero slash-less internal hrefs survive; canonical and hreflang URLs in built HTML all end in / (including /en/). Astro 6 auto-normalises Astro.url.pathname to the trailing-slash form when the flag is set, so BaseLayout's canonical/og:url emitter needs no source change. Workers Static Assets' default html_handling: "auto-trailing- slash" keeps external /ueber → /ueber/ redirects working at the edge — that is the expected behaviour, not the bug we are fixing. Two-stage integration review (spec-compliance + code-quality, parallel subagents) cleared the diff with non-blocking forward-looking notes (plan-template refinement for markdown editorial files; Pass-3 broadening of E.7's asset-filter blacklist). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Eliminates the one-hop
/ueber→/ueber/307 between Astro's canonical URLs and the URL Cloudflare Workers Static Assets serves natively. Closes backlog #1 (Phase E, G6).trailingSlash: 'never'→'always';canonicalise()insrc/lib/i18n.tsinverts to keep/add slash; counterparts map keys+values all slash-terminal with asymmetric'/' ↔ '/en/'root preserved.*Activereducers simplified), eight page templates' breadcrumb + product-card anchors, and two markdown editorial contact-page disclosure links.getLocaleFromPathdrops the now-deadcanonical === '/en'first condition (canonicalise now guarantees trailing slash).14 files / 49 ins / 45 del.
Verification
npm run check— 0 errors, 0 warnings.npm run build— clean.dist/-grep proves zero slash-less internal hrefs survive (filtered for assets)./(including/en/for EN root — Astro 6 auto-normalisesAstro.url.pathnameto the slash-terminal form, so noBaseLayout.astrosource change needed).plans/active/pass-2/g-e/cf-redirect-rules.md.Test plan
dev.curl -I https://dev.blackbrowedlabs.com/ueber/returns 200, not 307.curl -I https://dev.blackbrowedlabs.com/en/about/returns 200, not 307.curl -I https://dev.blackbrowedlabs.com/datenschutz/returns 200.curl -Ls -o /dev/null -w '%{num_redirects}\n' https://dev.blackbrowedlabs.com/ueber/returns0./ueber/,/en/about/,/datenschutz/,/en/privacy/, and one product detail URL — no redirect hop in the browser network tab./produkte/and/en/products/lands directly on the slug page with no 307.Production rollout waits for Phase F's full staging walkthrough (108-state Pass 2 matrix per
plans/active/pass-2/plan.md§Phase F.1).🤖 Generated with Claude Code