Prerender robots.txt so the static build keeps its sitemap reference
This commit is contained in:
+1
-1
@@ -17,7 +17,7 @@ This project starts from the `docus` i18n starter template (`extends: ['docus']`
|
|||||||
- **301 redirects (`routeRules`).** The old site served French content at root-level URLs (e.g. `/generalites/reseau/nat`, no locale prefix, on a separate `french` git branch). Restructuring into a single repo with `@nuxtjs/i18n`'s `/fr/...` prefix changed every French URL, which would otherwise break external links, bookmarks, and search-engine rankings for those pages built up over time. All 44 mappings use `statusCode: 301` explicitly — Nitro's default redirect status is 307 (temporary), which search engines don't treat as "please re-index this at the new URL" the way a 301 (permanent) does. There's deliberately **no** `/` → `/fr` redirect: root already serves English by default, and `@nuxtjs/i18n`'s `detectBrowserLanguage` already handles sending French-browser visitors to `/fr` automatically — a static redirect rule would just fight with that.
|
- **301 redirects (`routeRules`).** The old site served French content at root-level URLs (e.g. `/generalites/reseau/nat`, no locale prefix, on a separate `french` git branch). Restructuring into a single repo with `@nuxtjs/i18n`'s `/fr/...` prefix changed every French URL, which would otherwise break external links, bookmarks, and search-engine rankings for those pages built up over time. All 44 mappings use `statusCode: 301` explicitly — Nitro's default redirect status is 307 (temporary), which search engines don't treat as "please re-index this at the new URL" the way a 301 (permanent) does. There's deliberately **no** `/` → `/fr` redirect: root already serves English by default, and `@nuxtjs/i18n`'s `detectBrowserLanguage` already handles sending French-browser visitors to `/fr` automatically — a static redirect rule would just fight with that.
|
||||||
- **`site.trailingSlash: true`.** The site builds as a static export (`nuxt build`, deployed as static files on a web server) and the production host 301-redirects a bare `path` request to `path/` (verified against `docu.djeex.fr`), so canonical/og:url/sitemap URLs need to already carry the trailing slash — otherwise the canonical tag points at the very URL the server redirects away from, a loop that keeps the page out of search results. This is documented, official behavior for the wider Nuxt SEO ecosystem (`nuxtseo.com`'s "Trailing Slashes" guide), but Docus doesn't depend on `nuxt-seo-utils` for its canonical/og:url logic — it hand-rolls its own in `useSeo.ts` via a plain `joinURL(site.url, route.path)` that never checks this setting. That gap is why the items below exist alongside it.
|
- **`site.trailingSlash: true`.** The site builds as a static export (`nuxt build`, deployed as static files on a web server) and the production host 301-redirects a bare `path` request to `path/` (verified against `docu.djeex.fr`), so canonical/og:url/sitemap URLs need to already carry the trailing slash — otherwise the canonical tag points at the very URL the server redirects away from, a loop that keeps the page out of search results. This is documented, official behavior for the wider Nuxt SEO ecosystem (`nuxtseo.com`'s "Trailing Slashes" guide), but Docus doesn't depend on `nuxt-seo-utils` for its canonical/og:url logic — it hand-rolls its own in `useSeo.ts` via a plain `joinURL(site.url, route.path)` that never checks this setting. That gap is why the items below exist alongside it.
|
||||||
- **`nitro.prerender.autoSubfolderIndex: true`.** Docus sets this to `false` in its own `nuxt.config.ts`, which writes every route as `path.html` instead of `path/index.html` — the exact opposite of what the trailing-slash setup above needs, since the host would then redirect `/path` to `/path/` and find no directory there. Restoring the Nitro default puts the files back where the advertised URLs actually point.
|
- **`nitro.prerender.autoSubfolderIndex: true`.** Docus sets this to `false` in its own `nuxt.config.ts`, which writes every route as `path.html` instead of `path/index.html` — the exact opposite of what the trailing-slash setup above needs, since the host would then redirect `/path` to `/path/` and find no directory there. Restoring the Nitro default puts the files back where the advertised URLs actually point.
|
||||||
- **`nitro.prerender.routes: ['/']`.** Docus's `nitro:config` hook seeds one prerender route per locale (`/en`, `/fr`) but never `/` itself, so the site root has no file at all and 404s on a static host. Adding it renders `@nuxtjs/i18n`'s own root redirect to the default locale. (No `routeRules` entry for `/` instead: a hard redirect there would override i18n's `detectBrowserLanguage`, which is what currently sends French-browser visitors to `/fr`.)
|
- **`nitro.prerender.routes: ['/', '/robots.txt']`.** Docus's `nitro:config` hook seeds one prerender route per locale (`/en`, `/fr`) and `/sitemap.xml`, but never `/` or `/robots.txt` — both exist as server routes yet were never written to the static output, so both 404 on a static host. `/` loses i18n's redirect to the default locale, and robots.txt loses the `Sitemap:` line that points crawlers at the sitemap (the live site has this gap today: requesting `/robots.txt` returns the site's HTML). Prerendering them is all that's needed. (Deliberately not a `routeRules` redirect for `/`: a hard redirect there would override i18n's `detectBrowserLanguage`, which is what sends French-browser visitors to `/fr`.)
|
||||||
- **`experimental.defaults.nuxtLink.trailingSlash: 'append'`.** The native Nuxt-core (not `@nuxtjs/i18n`'s own, separate `trailingSlash` option — that one only affects `switchLocalePath()` and double-appends the slash on hreflang alternate links) way to make every `<NuxtLink>` href, including the ones i18n's `switchLocalePath` builds for hreflang tags, resolve with a trailing slash already, matching both `site.trailingSlash` and the directory-style files on disk.
|
- **`experimental.defaults.nuxtLink.trailingSlash: 'append'`.** The native Nuxt-core (not `@nuxtjs/i18n`'s own, separate `trailingSlash` option — that one only affects `switchLocalePath()` and double-appends the slash on hreflang alternate links) way to make every `<NuxtLink>` href, including the ones i18n's `switchLocalePath` builds for hreflang tags, resolve with a trailing slash already, matching both `site.trailingSlash` and the directory-style files on disk.
|
||||||
|
|
||||||
> **Do not add a global trailing-slash redirect middleware here.** An earlier revision had `app/middleware/trailing-slash.global.ts` 301-redirecting bare paths to their slash form. It broke the production build outright: Nitro's prerender crawler seeds on `/en` and `/fr`, the middleware turned both into redirect responses, and since Nitro extracts no links from a redirect the crawl stopped immediately — 31 routes and 22 HTML files instead of 557 and 146, with every content page missing. The host already performs that redirect server-side, so the middleware bought nothing.
|
> **Do not add a global trailing-slash redirect middleware here.** An earlier revision had `app/middleware/trailing-slash.global.ts` 301-redirecting bare paths to their slash form. It broke the production build outright: Nitro's prerender crawler seeds on `/en` and `/fr`, the middleware turned both into redirect responses, and since Nitro extracts no links from a redirect the crawl stopped immediately — 31 routes and 22 HTML files instead of 557 and 146, with every content page missing. The host already performs that redirect server-side, so the middleware bought nothing.
|
||||||
|
|||||||
+6
-4
@@ -84,10 +84,12 @@ export default defineNuxtConfig({
|
|||||||
// path to its slash form. Back to `path/index.html` so what's on disk
|
// path to its slash form. Back to `path/index.html` so what's on disk
|
||||||
// matches the URLs we advertise.
|
// matches the URLs we advertise.
|
||||||
autoSubfolderIndex: true,
|
autoSubfolderIndex: true,
|
||||||
// Docus only seeds `/en` and `/fr` (one per locale), so nothing is ever
|
// Docus only seeds `/en` and `/fr` (one per locale), so neither `/` nor
|
||||||
// written for `/` itself and the site root 404s on a static host. This
|
// `/robots.txt` is ever written and both 404 on a static host — `/` loses
|
||||||
// renders i18n's own root redirect to the default locale.
|
// the redirect to the default locale, and robots.txt loses the `Sitemap:`
|
||||||
routes: ['/'],
|
// line pointing crawlers at sitemap.xml. Both routes exist server-side,
|
||||||
|
// they just need to be prerendered.
|
||||||
|
routes: ['/', '/robots.txt'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// Keeps <NuxtLink> hrefs (including the ones i18n's switchLocalePath builds
|
// Keeps <NuxtLink> hrefs (including the ones i18n's switchLocalePath builds
|
||||||
|
|||||||
Reference in New Issue
Block a user