Skip to content

🐛 Specify canonical URL as frontside.com/interactors with staticalize - #333

Merged
taras merged 1 commit into
mainfrom
fix/canonical-frontside-home
Sep 30, 2026
Merged

taras merged 1 commit into
mainfrom
fix/canonical-frontside-home

Conversation

@taras

@taras taras commented Sep 28, 2026

Copy link
Copy Markdown
Member

Motivation

The deploy staticalizes with --base=https://interactors.netlify.app, so every
page tells Google the canonical copy is the Netlify one:

frontside.com/interactors/docs/quick-start
  <link rel="canonical" href="https://interactors.netlify.app/docs/quick-start">

frontside.com proxies this site and serves the same pages, so the two origins
are duplicates of each other — and the canonical points at the copy nobody
links to. The page frontside.com serves disclaims its own content in favour of
a Netlify subdomain, which is a good way to have the two treated as competing
sites rather than one.

Neither origin has a robots.txt, so nothing else settles it either.

thefrontside/effection#1248 fixed this for Effection last night; Effection now
serves <link rel="canonical" href="https://frontside.com/effection/..."> from
both origins. This is the same change for Interactors.

Approach

Both deploy jobs staticalize against the url readers actually visit:

-  --base=https://interactors.netlify.app
+  --base=https://frontside.com/interactors

useAbsoluteUrl already builds the canonical from the crawl origin, so
staticalize rewrites it along with og:url and every internal link. No
template changes are needed.

This depends on the staticalize 0.3.0 upgrade in #332, already on main:
honouring the path component of --base is what 0.3.0 added, and without it
the /interactors segment would be dropped.

The local staticalize task keeps --base=http://localhost:8000. It exists to
check a build by hand, and rewriting a local crawl onto production urls would
make every link in it unclickable.

Tests

Staticalized this site locally against the new base and read the output:

<link rel="canonical" href="https://frontside.com/interactors/docs/quick-start">
<meta property="og:url"  content="https://frontside.com/interactors/docs/quick-start">
href="https://frontside.com/interactors/docs/quick-start"

sitemap: 73 entries, all under https://frontside.com/interactors/, spelled <url>

73 pages, 8 assets, no errors.

Merge order

thefrontside/frontside.com#509 must land first. frontside.com mounts a
proxied site's sitemap by prefixing /interactors onto every entry. Once those
entries already carry the prefix, it doubles them and asks for
/interactors/interactors/..., which is nowhere — that is precisely what broke
frontside.com's deploy when Effection made this move, and #509 is the fix.

With #509 in, I confirmed the new sitemap mounts cleanly:

/interactors/                  -> /interactors/
/interactors/docs/quick-start  -> /interactors/docs/quick-start

Still to do

Graphgen has the same problem in a worse form: it advertises
graphgen-data.netlify.app and emits no canonical at all, so there is no
signal to correct. Moving its base fixes the sitemap and links, but giving it a
canonical means editing its Fresh templates.

@github-actions

github-actions Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Package Changes Through 0c88cb4

There are 1 changes which include @interactors/core with patch

Planned Package Versions

The following package releases are the planned based on the context of changes in this pull request.

package current next
@interactors/core 1.0.1 1.0.2
@interactors/keyboard 1.0.1 1.0.2
@interactors/html 1.0.1 1.0.2
@interactors/material-ui 5.0.0 5.0.1

Add another change file through the GitHub UI by following this link.


Read about change files or the docs at github.com/jbolda/covector

@github-actions

github-actions Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

🚀 Deploy Preview Ready!

@cowboyd

cowboyd commented Sep 28, 2026

Copy link
Copy Markdown
Member

How does this affect previews? Also, is this only for the production build? Something feels not quite right at the scoping level if we are building this with the base url as something that is completely outside. Ideally, we'd be able to use the app at both effection.netlify.app as well as the canonical base.

Wouldn't it fix it if we had an option in staticalize to --canonical https://frontside.com/effection that special cased <link rel="canonical" href="${base}"/> and other "canonical" urls like like ` etc..? Seems like that is the right fix.

Longer term, we need a plugin system for staticalize so that we can implement this outside the staticalize repo proper.

@taras

taras commented Sep 28, 2026 •

Copy link
Copy Markdown
Member Author

How does this affect previews?

It ensures that the preview's canonical URL is https://frontside.com/interactors.

This tells search bots that https://frontside.com/interactors is the main site they should prioritize.

Also, is this only for the production build?

In theory, this should be for all builds because any preview URL should be referencing the canonical URL. In practice, I think the preview URLs on Netlify are not available to search bots.

Something feels not quite right at the scoping level if we are building this with the base url as something that is completely outside. Ideally, we'd be able to use the app at both effection.netlify.app as well as the canonical base.

You are able to. It just controls what is treated as canonical URL.

Wouldn't it fix it if we had an option in staticalize to --canonical https://frontside.com/effection that special cased and other "canonical" urls like like ` etc..? Seems like that is the right fix.

I'm not sure I understand. We DO NOT want to erase the canonical URL because it's what communicates what the main URL is for this content.

Improve your UI testing experience and make maintenance easier. Interactors are composable page objects that work across Jest, Cypress, and more.
Effection is a structured concurrency and effects framework for JavaScript.

@cowboyd

cowboyd commented Sep 28, 2026

Copy link
Copy Markdown
Member

Right, but it replaces not only canonical urls, but all absolute urls. because the --base is now at a different site, which means that the only place that the build is valid is now at --base and really, --base should be where the target is going to be hosted at right? Otherwise, you won't necessarily be able to use the site at https://effection.netlify.app because internal base urls will be re-written to https://frontside.com/effection/${path-to-resource} even if it's just for a link.

Canonical urls are different than every other url in a site by design. They are specifically there not to point to the site, but to point to some other site that represents the "production address", so seems like since they are a special case, specifying them can be a special case.

@taras

taras commented Sep 28, 2026

Copy link
Copy Markdown
Member Author

Oh, i see what you mean, because it's defining base URL as the argument but it only uses the base URL when it needs a canonical URL.

@taras

taras commented Sep 28, 2026

Copy link
Copy Markdown
Member Author

This will allow us to split base and canonical thefrontside/staticalize#22

@taras taras changed the title 🐛 Say that this site lives at frontside.com/interactors 🐛 Specify canonical URL as frontside.com/interactors with staticalize Sep 28, 2026
@taras
taras force-pushed the fix/canonical-frontside-home branch from be41d1b to 026a1ec Compare September 30, 2026 00:30
taras added a commit to thefrontside/graphgen that referenced this pull request Sep 30, 2026
frontside.com proxies this site and serves the same pages, so the two
origins are duplicates of each other. Nothing said which one is the
original: the docs emitted no canonical at all, and the deploy staticalized
with `--base=https://graphgen-data.netlify.app`, so every link and every
sitemap entry named the hosting url rather than the one readers visit.

Two identical sites and no signal is how they end up competing for the same
searches instead of counting as one page. Neither origin has a robots.txt
either, so nothing else settles it.

The docs pages now name the url they are read at, built from the request so
that a local crawl still names localhost. staticalize 0.3.1 rewrites it
onto `--canonical` while the rest of the build stays on `--base`, so the
Netlify copy remains readable on its own and its sitemap still says so.
Only `routes/docs/[...slug].tsx` needs it: `index.tsx` is a 307 with no
markup, and `[name].tsx` is not in the sitemap.

staticalize comes from npm rather than jsr. Deno's minimum dependency age
refuses a jsr version for its first 24 hours, and both deploy jobs run this
task, so a jsr specifier would fail every deploy on the day of a release.
npm resolution is not subject to it. The package publishes a `bin` rather
than a `/cli` export, so the specifier loses its subpath.

0.3.1 also restored the default for `--retries`, so the flag 0.3.0 forced us
to pass goes away with it.

thefrontside/effection#1255 and thefrontside/interactors#333 make the same
move; `fix-static-css.ts` only rewrites Twind css in html and is unaffected.
@taras
taras force-pushed the fix/canonical-frontside-home branch from 026a1ec to 25fc2d3 Compare September 30, 2026 13:31
The deploy staticalized with `--base=https://interactors.netlify.app`, so
every page told Google the canonical copy was the Netlify one:

    frontside.com/interactors/docs/quick-start
      <link rel="canonical" href="https://interactors.netlify.app/docs/quick-start">

frontside.com proxies this site and serves the same pages, so the two are
duplicates of each other and the canonical pointed at the copy nobody links
to. The page frontside.com serves was disclaiming its own content.

staticalize 0.3.1 separates where a build is hosted from the url it is
published at, so `--base` stays where the bytes are and `--canonical` names
the address readers arrive at. A preview is then browsable on its own alias
while still telling search engines to index production.

`useAbsoluteUrl` already builds the canonical from the crawl origin, so
staticalize rewrites it along with `og:url`; no template change is needed.

The task takes staticalize from npm rather than jsr. Deno's minimum
dependency age refuses a jsr version for its first 24 hours, which would
block this task on the day of every staticalize release; npm resolution is
not subject to it. The package publishes a `bin` rather than a `/cli`
export, so the specifier loses its subpath.

0.3.1 also restored the default for `--retries`, so the flag 0.3.0 forced us
to pass goes away with it.
@taras
taras force-pushed the fix/canonical-frontside-home branch from 25fc2d3 to 0c88cb4 Compare September 30, 2026 13:35
@taras
taras merged commit 9965a37 into main Sep 30, 2026
5 checks passed
@taras
taras deleted the fix/canonical-frontside-home branch September 30, 2026 13:37

This branch was successfully deployed

1 active deployment
Preview — 0c88cb48 Deployed Sep 30, 2026 by taras via deploy-preview #40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants