diff --git a/frontend/scripts/generate-sitemap.mjs b/frontend/scripts/generate-sitemap.mjs index c378f03b..b591f55d 100644 --- a/frontend/scripts/generate-sitemap.mjs +++ b/frontend/scripts/generate-sitemap.mjs @@ -64,6 +64,11 @@ const exampleUrls = exampleIds.map((id) => ({ priority: 0.6, })); +// Every carries a trailing slash. nginx serves the prerendered route +// files as `/index.html` and 301-redirects the slash-less form to add +// the slash, so a slash-less sitemap URL is fetched as a redirect and filed +// under "Page with redirect" in Search Console. Matching the served (slash) +// form keeps the sitemap URL == canonical == 200, with no redirect hop. const xml = ` @@ -71,7 +76,7 @@ ${indexable .map( (r) => ` - ${DOMAIN}${r.path} + ${DOMAIN}${r.path}${r.path.endsWith('/') ? '' : '/'} ${TODAY} ${r.changefreq ?? 'monthly'} ${r.priority ?? 0.5} @@ -82,7 +87,7 @@ ${exampleUrls .map( (u) => ` - ${u.loc} + ${u.loc}/ ${u.lastmod} ${u.changefreq} ${u.priority} diff --git a/frontend/scripts/prerender-seo.mjs b/frontend/scripts/prerender-seo.mjs index 3e383c1c..24416c3a 100644 --- a/frontend/scripts/prerender-seo.mjs +++ b/frontend/scripts/prerender-seo.mjs @@ -33,6 +33,12 @@ if (!existsSync(join(distDir, 'index.html'))) { const baseHtml = readFileSync(join(distDir, 'index.html'), 'utf-8'); const DOMAIN = 'https://velxio.dev'; +// nginx serves each prerendered route as `/index.html` and +// 301-redirects the slash-less URL to add the trailing slash. Canonical + +// og:url must therefore use the slash form (== the served URL == the sitemap +// entry), or Google sees a canonical that points to a redirecting URL. +const withSlash = (u) => (u.endsWith('/') ? u : `${u}/`); + // ── Mock browser globals for SSR ──────────────────────────────────────────── // Zustand's persist middleware and some components access these at import time. if (typeof globalThis.localStorage === 'undefined') { @@ -96,7 +102,7 @@ try { ); // Add/replace canonical URL - const canonicalTag = ``; + const canonicalTag = ``; if (html.includes(']*\/>/, canonicalTag); } else { @@ -114,7 +120,7 @@ try { ); html = html.replace( /`; + const canonicalTag = ``; if (html.includes(']*\/>/, canonicalTag); } else { @@ -178,7 +184,7 @@ try { html = html.replace(/