diff --git a/app/pages/docs/[...slug].vue b/app/pages/docs/[...slug].vue index 9209835fd..651621a7e 100644 --- a/app/pages/docs/[...slug].vue +++ b/app/pages/docs/[...slug].vue @@ -79,7 +79,7 @@ watch(page, (page) => { }, { immediate: true }) // Get the -2 item of the breadcrumb -const currentSectionTitle = computed(() => headerLinks.value[0].children.find(link => path.value.includes(link.to))?.label || findPageBreadcrumb(navigation.value, path.value).slice(-1)[0].title) +const currentSectionTitle = computed(() => headerLinks.value[0].children.find(link => path.value.includes(link.to))?.label || findPageBreadcrumb(navigation.value, path.value).slice(-1)[0]?.title || page.value?.title) const breadcrumb = computed(() => { const links = mapContentNavigation(findPageBreadcrumb(navigation.value, path.value)).map(link => ({ diff --git a/content.config.ts b/content.config.ts index 2240c86d5..677696ad8 100644 --- a/content.config.ts +++ b/content.config.ts @@ -10,7 +10,8 @@ const docsV3Source = { const docsV4Source = { cwd: process.env.NUXT_V4_PATH ?? undefined, - repository: !process.env.NUXT_V4_PATH ? 'https://github.com/nuxt/nuxt/tree/4.x' : undefined, + // TODO: revert to 4.x branch before merging + repository: !process.env.NUXT_V4_PATH ? 'https://github.com/nuxt/nuxt/tree/error-context' : undefined, include: 'docs/**/*', exclude: ['docs/**/*.json'], prefix: '/docs/4.x' diff --git a/nuxt.config.ts b/nuxt.config.ts index eda446ac7..43d4a3b6e 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -117,6 +117,7 @@ export default defineNuxtConfig({ '/docs/3.x/getting-started/introduction': { prerender: true }, '/docs/4.x/getting-started/introduction': { prerender: true }, '/docs/5.x/getting-started/introduction': { prerender: true }, + '/docs/4.x/errors': { prerender: true }, '/modules': { prerender: true }, '/modules/**': { isr: 60 * 60 }, '/changelog': { isr: 60 * 60 }, diff --git a/server/middleware/error-docs-redirect.ts b/server/middleware/error-docs-redirect.ts new file mode 100644 index 000000000..8407b175f --- /dev/null +++ b/server/middleware/error-docs-redirect.ts @@ -0,0 +1,19 @@ +/** + * Redirect unversioned error doc paths to the current default version. + * + * The Nuxt runtime links to https://nuxt.com/docs/errors/E1001 (unversioned). + * This middleware redirects those paths to the current default docs version + * (e.g., /docs/4.x/errors/e1001) so the content can be resolved. + * + * The error code is lowercased to match the content collection path. + */ +export default defineEventHandler((event) => { + const path = getRequestURL(event).pathname + + // Match /docs/errors/... but NOT /docs/3.x/errors/... or /docs/4.x/errors/... + const match = path.match(/^\/docs\/errors\/(.+)$/) + if (match?.[1]) { + // TODO: update to /docs/5.x when Nuxt 5 is the default + return sendRedirect(event, `/docs/4.x/errors/${match[1].toLowerCase()}`, 302) + } +}) diff --git a/server/routes/e/[code].get.ts b/server/routes/e/[code].get.ts new file mode 100644 index 000000000..baaace893 --- /dev/null +++ b/server/routes/e/[code].get.ts @@ -0,0 +1,24 @@ +/** + * Short URL handler for Nuxt error codes. + * + * Redirects /e/NUXT_E1001 → /docs/4.x/errors/e1001 + * Redirects /e/NUXT_B1001 → /docs/4.x/errors/b1001 + * + * The error code format is NUXT_ followed by E or B and 1-4 digits. + * The NUXT_ prefix is stripped, the code is lowercased, and the user + * is redirected to the current default docs version. + */ +export default defineEventHandler((event) => { + const code = getRouterParam(event, 'code') + + // Validate: must be NUXT_ followed by E or B and 1-4 digits + if (!code || !/^NUXT_[EB]\d{1,4}$/i.test(code)) { + throw createError({ statusCode: 404, statusMessage: 'Not found' }) + } + + // Strip the NUXT_ prefix and lowercase → e1001 or b1001 + const errorCode = code.replace('NUXT_', '').toLowerCase() + + // TODO: update to /docs/5.x when Nuxt 5 is the default + return sendRedirect(event, `/docs/4.x/errors/${errorCode}`, 302) +})