fix(site): canonicalise pages to the URL the site publishes - #211
Merged
Conversation
Starlight derives a page's canonical URL from the file it writes to disk. Under `build.format: "file"` that file is `start/install.html`, so every page shipped `<link rel="canonical" href="https://fanout.run/start/install.html">` and an `og:url` to match. Nothing else on the site uses that form. The sitemap lists `/start/install`, every internal link points at `/start/install`, `llms.txt` points at `/start/install.md`, and Cloudflare Pages — where the site is published — serves the extensionless path and 301s the `.html` one to it. The single tag whose job is to state the page's real address was naming a redirect, on all 33 pages, and the sitemap and the canonicals disagreed about which URLs exist. Starlight's own `formatCanonical` returns the href untouched when the build format is "file", which is right for a server that only serves `foo.html` and wrong for this one, so the correction is a route middleware rather than a configuration flag. It rewrites the two tags in place: a second `<link rel="canonical">` with a different href is worse than one wrong href, because a crawler that sees the pair discards both. `scripts/check-canonical.mjs` joins the build and asserts the three properties that have to hold together — no `.html` in the canonical, `og:url` agreeing with it, and the canonical present in the sitemap. The regression it guards against produces a build that looks perfect and only surfaces in a crawler weeks later.
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.
Starlight derives a page's canonical URL from the file it writes to disk.
Under
build.format: "file"that file isstart/install.html, so everypage shipped
<link rel="canonical" href="https://fanout.run/start/install.html">and an
og:urlto match.Nothing else on the site uses that form. The sitemap lists
/start/install, every internal link points at/start/install,llms.txtpoints at/start/install.md, and Cloudflare Pages — where thesite is published — serves the extensionless path and 301s the
.htmloneto it. The single tag whose job is to state the page's real address was
naming a redirect, on all 33 pages, and the sitemap and the canonicals
disagreed about which URLs exist.
Starlight's own
formatCanonicalreturns the href untouched when thebuild format is "file", which is right for a server that only serves
foo.htmland wrong for this one, so the correction is a route middlewarerather than a configuration flag. It rewrites the two tags in place: a
second
<link rel="canonical">with a different href is worse than onewrong href, because a crawler that sees the pair discards both.
scripts/check-canonical.mjsjoins the build and asserts the threeproperties that have to hold together — no
.htmlin the canonical,og:urlagreeing with it, and the canonical present in the sitemap. Theregression it guards against produces a build that looks perfect and only
surfaces in a crawler weeks later.
https://claude.ai/code/session_01D39DJ5DrKHadUedNMSmAUn