Commit 3d714c9
feat(seo): source-level SEO overhaul (canonical, hreflang, JSON-LD, per-page OG, sitemap) (#480)
* docs(seo): add SEO overhaul design spec
Design doc for the source-level SEO overhaul: canonical + hreflang via
the existing head-rewrite middleware fed by a baked route->locales map,
meta-description fallback, JSON-LD, sitemap lastmod/alternates, per-page
OG images, and head polish. Deployment/migration explicitly out of scope.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(seo): add SEO overhaul implementation plan
11 TDD tasks: pure seo/ url+hreflang+jsonld helpers, baked route-map.gen.ts,
head-middleware injection, sitemap lastmod/alternates, content descriptions,
blog dates, per-page OG images, and head polish.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(seo): add pure canonical/locale URL helpers
* docs(seo): fix plan neutralPath to match splitLocale (en not stripped)
* feat(seo): generate committed route->locales + blog-date map
* feat(seo): add hreflang alternate link builder
* feat(seo): add JSON-LD builder (WebSite/Org/TechArticle/BlogPosting)
* docs(seo): fix plan JSON-LD breadcrumb existsByPage to per-locale Record
* feat(seo): inject canonical, hreflang, JSON-LD, desc fallback in head middleware
* feat(seo): sitemap git lastmod + xhtml:link hreflang alternates
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(seo): add meta descriptions to concept + function + module-init docs
* docs(seo): Task 8 guard - maintain blog dates in pages/, never run convert-content
* feat(seo): add blog dates + descriptions (fixes RSS + BlogPosting date)
* feat(seo): generate per-page OG images at build (satori + resvg)
Docs + blog routes get a branded 1200x630 title card at
dist/client/og/<route>.png via satori (React node -> SVG) + resvg
(SVG -> PNG). Islands keep the static og-v2.png. Fonts come from the
static TTFs shipped by @expo-google-fonts (Manrope 700 title, Inter 600
wordmark, Noto Sans SC 700 as CJK fallback so cn titles render).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(seo): move OG build deps to devDependencies; lazy-load OG fonts
satori + @resvg/resvg-js are build-only (imported only by
scripts/generate-og-images.mjs via vite.config.ts); move them from
dependencies to devDependencies so all five build-only packages (incl the
three @expo-google-fonts/*) live together.
Read the three font TTFs (~11 MB) lazily + memoized in a getFonts()
accessor instead of at module top level, so importing the module (dev
server, vp test) no longer reads them; only renderOg does. Output PNGs
are byte-identical.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(seo): per-page og:image + twitter card; drop static image duplicates
* fix(seo): use en OG image on i18n-fallback pages (avoid 404 cn/pt-BR og:image)
* feat(seo): localized h1s, PWA manifest, theme-color, apple-touch-icon, img alt
* fix(seo): escape head/JSON-LD, argv git, fallback JSON-LD locale, trailing-slash canonical
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(seo): decode pre-encoded head values before re-escaping (no double-encode)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(seo): normalize /en prefix in og:image path (avoid /og/en/*.png 404)
The deploy prerenderer dispatches pages by their internal `/en/docs|blog/…`
route, bypassing the edge `/en/* -> /:splat` redirect, so a non-fallback en
page reaches ogImageUrl with a raw `en/` prefix. og-image.ts derived the
served path from the raw publicPath, emitting `https://napi.rs/og/en/docs/….png`
— a PNG the generator never writes (en cards are unprefixed), so crawlers of
the baked HTML got a 404 og:image. canonical/og:url were already correct
(selfCanonical normalizes en -> root); only og:image leaked the prefix.
Rebuild `served` from (locale + neutral) to mirror fileToRoute's shape: default
locale drops its prefix, cn/pt-BR keep theirs. Adds regression tests for the
/en/ (+ trailing slash) and pt-BR cases.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>1 parent e4ccc55 commit 3d714c9
74 files changed
Lines changed: 3515 additions & 36 deletions
File tree
- components
- landing/features
- content/docs/concepts
- docs/superpowers
- plans
- specs
- lib
- i18n
- seo
- middleware
- pages
- cn
- blog
- docs/concepts
- en
- blog
- docs/concepts
- pt-BR
- docs/concepts
- public
- scripts
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
143 | 143 | | |
144 | 144 | | |
145 | 145 | | |
146 | | - | |
| 146 | + | |
147 | 147 | | |
148 | 148 | | |
149 | 149 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
66 | 66 | | |
67 | 67 | | |
68 | 68 | | |
| 69 | + | |
69 | 70 | | |
70 | 71 | | |
71 | 72 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
3 | 7 | | |
4 | | - | |
| 8 | + | |
5 | 9 | | |
6 | 10 | | |
7 | | - | |
| 11 | + | |
8 | 12 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
3 | 7 | | |
4 | | - | |
| 8 | + | |
5 | 9 | | |
6 | 10 | | |
7 | | - | |
| 11 | + | |
8 | 12 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
| 3 | + | |
3 | 4 | | |
4 | 5 | | |
5 | 6 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
| 3 | + | |
3 | 4 | | |
4 | 5 | | |
5 | 6 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
| 3 | + | |
3 | 4 | | |
4 | 5 | | |
5 | 6 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
| 3 | + | |
3 | 4 | | |
4 | 5 | | |
5 | 6 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
| 3 | + | |
3 | 4 | | |
4 | 5 | | |
5 | 6 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
| 3 | + | |
3 | 4 | | |
4 | 5 | | |
5 | 6 | | |
| |||
0 commit comments