Repository navigation
✨ Separate where a build is hosted from the url it is canonically at #21
Description
Motivation
--base currently answers two different questions at once:
- where these bytes live — what
a[href],[src], and asset links should
point at - what this content is called — what
<link rel="canonical">and
<meta property="og:url">should claim
For an ordinary site those coincide, so nothing forced them apart. They diverge
the moment a site is served from one origin and published at another, which is
how the Frontside sites work: Effection is hosted at effection.netlify.app and
published at frontside.com/effection, and the same holds for Interactors and
Graphgen.
Today the only way to get a correct canonical is to point --base at the
published url, which then drags every other url along with it. The build becomes
valid only at the published address, and a preview cannot say "index production
instead of me" without also rewriting its own navigation onto production.
It has already cost something
thefrontside/effection#1248 moved Effection's production --base to
https://frontside.com/effection to get the canonical right. That also moved the
sitemap, so effection.netlify.app/sitemap.xml began listing
https://frontside.com/effection/.... frontside.com mounts a proxied site's
sitemap by prefixing /effection onto every entry, so the prefix landed twice
and every url 404'd:
Error: could not download http://127.0.0.1:8005/effection/effection/docs/resources
Error: GET ... responded 404 Not Found
519 errors, and frontside.com's deploy has been failing since
(thefrontside/frontside.com#509 is the fix on that side). None of that was the
intent of #1248 — it followed from --base meaning two things.
What is actually being rewritten
Worth recording, because it narrows the problem. On the deployed builds, no
navigation was rewritten at all:
| effection.netlify.app | pr-333 interactors preview | |
|---|---|---|
| relative nav links, untouched | 54 | 28 |
| absolute links still on the hosting origin | 0 | 0 |
| absolute urls rewritten to frontside.com | 6 | 4 |
Every one of those 6 and 4 is identity metadata:
<link rel="canonical"> <meta property="og:url">
<meta property="og:image"> <meta name="twitter:image">
<link rel="alternate" hreflang=…>
Both sites navigate with relative hrefs, so they still browse standalone. The
conflation is not breaking navigation today — it works by luck rather than by
design, and it did break the sitemap.
Approach
Add --canonical, defaulting to --base, so every existing invocation behaves
exactly as it does now. rebase() then gets called with one of two targets
depending on what the url is for:
| selector | rebased onto | why |
|---|---|---|
link[rel=canonical] |
canonical | names the published page |
meta[property=og:url] |
canonical | the same claim in another vocabulary |
link[rel=alternate] |
canonical | hreflang should name the indexed url |
a[href], [src], other link[href] |
base | where this build's bytes are |
A preview then expresses what it actually means:
--base=https://pr-333--interactors.netlify.app # browsable on its own
--canonical=https://frontside.com/interactors # index production, not me
Open questions
og:image / twitter:image. Assets, so base by the rule above — a
preview shows its own card. But a social card arguably should always be
production's. Listed as base in the table; easy to move.
The sitemap. It maps this deployment, so base keeps a preview from
listing production urls, and keeps frontside.com's prefixing working as it
always did. Google's guidance is that sitemaps list canonical urls, which argues
the other way.
Textual bodies (#17). The sharp one. #1248's intent was that production
documents advertise production, which it got by pointing --base there. Split
canonical out, leave text on base, and llms.txt goes back to naming the
Netlify origin — a regression of that intent. canonical seems right, since
llms.txt is a map telling agents where the docs live. The exception is a
feed's rel="self", which should name where the feed is, and a blind text
substitution cannot tell the two apart.
What the consuming sites do afterwards
- Interactors — flag change only. It already emits its canonical from the
crawl origin, which is what lets staticalize rewrite it. - Graphgen — needs the
<link rel="canonical">it never had
(🐛 Specify canonical url as frontside.com/graphgen with staticalize graphgen#74), then the same flag change. - Effection — gets simpler. Its canonical is currently emitted by the site
from its own base option, so staticalize skips it as off-origin. If
staticalize owns canonical, that plumbing collapses and Effection stops having
two different flags named--base.
Activity