Skip to content

SITE_URL and middleware's CANONICAL_HOST are two literals for one value, with nothing enforcing agreement #205

Description

@hotlong

Residual of #199, filed rather than left to dissolve into that merge. The dev who did #204 named it and correctly declined to do it, because the repair needs a fourth file the card had not granted.

State after #204

app/layout.tsx now derives metadataBase from SITE_URL. middleware.ts deliberately does not import it, and that decision is sound and measured — pointing middleware.ts at @/lib/seo grows the edge runtime bundle from 149,491 B to 14,849,913 B, roughly 99x, because lib/seo.ts imports lib/source.ts and pulls the whole MDX collection into the edge graph.

The part that makes it a card rather than a note: in that state next build still exits 0. No gate reports it. This app deploys to Cloudflare Workers, so the cost arrives at deploy time.

So both sides keep a literal, and both now carry a comment stating why. What neither carries is enforcement:

location value
lib/seo.ts SITE_URL the canonical host, for all page and route metadata
middleware.ts CANONICAL_HOST the same host, for the domain redirect

Nothing fails if they drift. If they drift, the redirect sends traffic to one host while every canonical tag, og:url and hreflang alternate on the site names another — which is the specific failure this whole run of cards has been closing.

The repair

A leaf module — apps/docs/lib/site.ts — exporting the host string and nothing else, imported by both lib/seo.ts and middleware.ts.

It only works if it is genuinely a leaf. It must import nothing: not @/lib/source, not @/lib/i18n, not fumadocs, not anything that transitively reaches the MDX collection. If it imports anything, it reintroduces the 99x bundle and the build will still exit 0 while it does.

Acceptance — the size is the acceptance criterion, not a sanity check

  • Read the edge runtime JS size from the build output before and after, and report both numbers. It must stay at the current baseline (149,491 B at 3433803, but re-measure rather than assuming that figure still holds). A build that exits 0 proves nothing here.
  • If it grows at all, stop and report. Do not ship it and note the size.
  • Rendered metadata must be unchanged. Use fix(docs): collapse the metadataBase hostname into SITE_URL, record the middleware decision #204's method — extract every URL-bearing head tag across the prerendered pages and diff those rows. A raw byte diff of .next is useless: Next salts every build with a fresh build ID, so all outputs differ between any two builds.
  • The domain redirect must still work. fix(docs): collapse the metadataBase hostname into SITE_URL, record the middleware decision #204 exercised it against a running server across six cases including query preservation and the legacy /cn/ locale control; reuse that table.

Priority

Low. This is cleanup of a duplication that is currently correct and documented on both sides. It is filed because "currently correct and documented" is exactly the state that decays silently, and because the repair is small if the leaf-module constraint is respected.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions