From e6718ada719e8931f643e1184aee354d4698c1da Mon Sep 17 00:00:00 2001 From: SnapOtter Date: Tue, 21 Jul 2026 15:22:15 +0800 Subject: [PATCH] fix(seo): emit clean docs URLs and de-index the demo (#598) The docs sitemap listed .html URLs that Cloudflare Pages 308-redirects to their clean form, while every page's canonical/hreflang already pointed at the clean URL. Google indexed the redirecting .html variant and picked its own canonical (GSC "Duplicate, Google chose different canonical"), and burned crawl budget re-fetching redirecting URLs. Setting VitePress cleanUrls:true makes the sitemap and internal links extension-less so they match the canonicals. CF Pages already serves the clean URL at 200 and 308s the .html form, so no hosting change is needed and legacy .html hits consolidate. Also mark demo.snapotter.com noindex: it mirrors the real app under the same domain property, so its routes were being crawled and indexed as thin, duplicate pages. --- apps/demo/index.html | 4 +++- apps/docs/.vitepress/config.mts | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/demo/index.html b/apps/demo/index.html index ec95b758..a7114d8d 100644 --- a/apps/demo/index.html +++ b/apps/demo/index.html @@ -14,7 +14,9 @@ - + +
diff --git a/apps/docs/.vitepress/config.mts b/apps/docs/.vitepress/config.mts index 03ca975e..65deec84 100644 --- a/apps/docs/.vitepress/config.mts +++ b/apps/docs/.vitepress/config.mts @@ -117,6 +117,14 @@ export default defineConfig({ outDir: "./.vitepress/dist", ignoreDeadLinks: [/localhost/], + // Extension-less URLs in both internal links and the sitemap, so they match + // the clean canonical/hreflang emitted in transformHead below. Without this + // the sitemap listed .html URLs that Cloudflare Pages 308-redirects to the + // clean form, so Google indexed the redirecting variant and overrode our + // canonical (GSC "Duplicate, Google chose different canonical"). CF Pages + // serves the clean URL at 200, so no extra server config is needed. + cleanUrls: true, + sitemap: { hostname: "https://docs.snapotter.com" }, head: [