diff --git a/packages/nuxt/src/core/nitro.ts b/packages/nuxt/src/core/nitro.ts index 2e6fcad67a..c0114b2ea7 100644 --- a/packages/nuxt/src/core/nitro.ts +++ b/packages/nuxt/src/core/nitro.ts @@ -189,6 +189,15 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) { } } + // Add backward-compatible middleware to respect `x-nuxt-no-ssr` header + if (nuxt.options.experimental.respectNoSSRHeader) { + nitroConfig.handlers = nitroConfig.handlers || [] + nitroConfig.handlers.push({ + handler: resolve(distDir, 'core/runtime/nitro/no-ssr'), + middleware: true + }) + } + // Register nuxt protection patterns nitroConfig.rollupConfig!.plugins = await nitroConfig.rollupConfig!.plugins || [] nitroConfig.rollupConfig!.plugins = Array.isArray(nitroConfig.rollupConfig!.plugins) ? nitroConfig.rollupConfig!.plugins : [nitroConfig.rollupConfig!.plugins] diff --git a/packages/nuxt/src/core/runtime/nitro/no-ssr.ts b/packages/nuxt/src/core/runtime/nitro/no-ssr.ts new file mode 100644 index 0000000000..556c3f98e5 --- /dev/null +++ b/packages/nuxt/src/core/runtime/nitro/no-ssr.ts @@ -0,0 +1,8 @@ +import { defineEventHandler, getRequestHeader } from 'h3' + +export default defineEventHandler((event) => { + if (getRequestHeader(event, 'x-nuxt-no-ssr')) { + event.context.nuxt = event.context.nuxt || {} + event.context.nuxt.noSSR = true + } +}) diff --git a/packages/nuxt/src/core/runtime/nitro/renderer.ts b/packages/nuxt/src/core/runtime/nitro/renderer.ts index 19439bb7fa..9336bdfa5a 100644 --- a/packages/nuxt/src/core/runtime/nitro/renderer.ts +++ b/packages/nuxt/src/core/runtime/nitro/renderer.ts @@ -213,7 +213,7 @@ export default defineRenderHandler(async (event) => { runtimeConfig: useRuntimeConfig() as NuxtSSRContext['runtimeConfig'], noSSR: !!(process.env.NUXT_NO_SSR) || - !!(event.node.req.headers['x-nuxt-no-ssr']) || + event.context.nuxt?.noSSR || routeOptions.ssr === false || (process.env.prerender ? PRERENDER_NO_SSR_ROUTES.has(url) : false), error: !!ssrError, diff --git a/packages/schema/src/config/experimental.ts b/packages/schema/src/config/experimental.ts index 1d696fbcb5..22f5e03c12 100644 --- a/packages/schema/src/config/experimental.ts +++ b/packages/schema/src/config/experimental.ts @@ -158,6 +158,9 @@ export default defineUntypedSchema({ * * This can be disabled for most Nuxt sites to reduce the client-side bundle by ~0.5kb. */ - polyfillVueUseHead: true + polyfillVueUseHead: true, + + /** Allow disabling Nuxt SSR responses by setting the `x-nuxt-no-ssr` header. */ + respectNoSSRHeader: false, } }) diff --git a/test/fixtures/basic/nuxt.config.ts b/test/fixtures/basic/nuxt.config.ts index 8d0cba4650..c6a7ab5b31 100644 --- a/test/fixtures/basic/nuxt.config.ts +++ b/test/fixtures/basic/nuxt.config.ts @@ -184,6 +184,7 @@ export default defineNuxtConfig({ } }, experimental: { + respectNoSSRHeader: true, clientFallback: true, restoreState: true, inlineSSRStyles: id => !!id && !id.includes('assets.vue'),