From b4da29d75dfe1bf7bd3c1599983b32f1a4299813 Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Fri, 30 Sep 2022 21:29:44 +0100 Subject: [PATCH 1/4] feat(nuxt): add `ssr` route rule for easily enable spa mode --- packages/nuxt/src/core/nitro.ts | 24 ++++++++++++------- .../nuxt/src/core/runtime/nitro/renderer.ts | 8 +++++++ 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/packages/nuxt/src/core/nitro.ts b/packages/nuxt/src/core/nitro.ts index d66578d243f..49212ea125e 100644 --- a/packages/nuxt/src/core/nitro.ts +++ b/packages/nuxt/src/core/nitro.ts @@ -16,7 +16,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) { // Resolve config const _nitroConfig = ((nuxt.options as any).nitro || {}) as NitroConfig - const nitroConfig: NitroConfig = defu(_nitroConfig, { + const nitroConfig: NitroConfig = defu(_nitroConfig, { rootDir: nuxt.options.rootDir, workspaceDir: nuxt.options.workspaceDir, srcDir: join(nuxt.options.srcDir, 'server'), @@ -65,10 +65,10 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) { ...(nuxt.options.dev ? [] : [ - ...nuxt.options.experimental.externalVue ? [] : ['vue', '@vue/'], - '@nuxt/', - nuxt.options.buildDir - ]), + ...nuxt.options.experimental.externalVue ? [] : ['vue', '@vue/'], + '@nuxt/', + nuxt.options.buildDir + ]), 'nuxt/dist', 'nuxt3/dist', distDir @@ -79,10 +79,10 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) { ? {} : { - 'vue/compiler-sfc': 'vue/compiler-sfc', - 'vue/server-renderer': 'vue/server-renderer', - vue: await resolvePath(`vue/dist/vue.cjs${nuxt.options.dev ? '' : '.prod'}.js`) - }, + 'vue/compiler-sfc': 'vue/compiler-sfc', + 'vue/server-renderer': 'vue/server-renderer', + vue: await resolvePath(`vue/dist/vue.cjs${nuxt.options.dev ? '' : '.prod'}.js`) + }, // Vue 3 mocks 'estree-walker': 'unenv/runtime/mock/proxy', '@babel/parser': 'unenv/runtime/mock/proxy', @@ -227,3 +227,9 @@ async function resolveHandlers (nuxt: Nuxt) { devHandlers } } + +declare module 'nitropack' { + interface NitroRouteOption { + ssr?: boolean + } +} diff --git a/packages/nuxt/src/core/runtime/nitro/renderer.ts b/packages/nuxt/src/core/runtime/nitro/renderer.ts index fcb56a73f75..2a0553e40ed 100644 --- a/packages/nuxt/src/core/runtime/nitro/renderer.ts +++ b/packages/nuxt/src/core/runtime/nitro/renderer.ts @@ -3,6 +3,7 @@ import type { RenderResponse } from 'nitropack' import type { Manifest } from 'vite' import { appendHeader, getQuery } from 'h3' import devalue from '@nuxt/devalue' +import { createRouter as createMatcher } from 'radix3' import { joinURL } from 'ufo' import { renderToString as _renderToString } from 'vue/server-renderer' import { useRuntimeConfig, useNitroApp, defineRenderHandler } from '#internal/nitro' @@ -103,6 +104,9 @@ const getSPARenderer = lazyCachedFunction(async () => { return { renderToString } }) +// Set up route rule matcher +const routerOptions = createMatcher({ routes: useRuntimeConfig().nitro.routes }) + const PAYLOAD_CACHE = (process.env.NUXT_PAYLOAD_EXTRACTION && process.env.prerender) ? new Map() : null // TODO: Use LRU cache const PAYLOAD_URL_RE = /\/_payload(\.[a-zA-Z0-9]+)?.js(\?.*)?$/ @@ -125,6 +129,9 @@ export default defineRenderHandler(async (event) => { } } + // TODO: share across endpoints on event context + const routeOptions = routerOptions.lookup(url) || {} + // Initialize ssr context const ssrContext: NuxtSSRContext = { url, @@ -135,6 +142,7 @@ export default defineRenderHandler(async (event) => { noSSR: !!(process.env.NUXT_NO_SSR) || !!(event.req.headers['x-nuxt-no-ssr']) || + routeOptions.ssr === false || (process.env.prerender ? PRERENDER_NO_SSR_ROUTES.has(url) : false), error: !!ssrError, nuxt: undefined!, /* NuxtApp */ From 7c5eaec0fd1f087dc166a308dcfde1c1b024b954 Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Fri, 30 Sep 2022 21:33:32 +0100 Subject: [PATCH 2/4] style: for goodness' sake --- packages/nuxt/src/core/nitro.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/nuxt/src/core/nitro.ts b/packages/nuxt/src/core/nitro.ts index 49212ea125e..39c95bd8017 100644 --- a/packages/nuxt/src/core/nitro.ts +++ b/packages/nuxt/src/core/nitro.ts @@ -16,7 +16,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) { // Resolve config const _nitroConfig = ((nuxt.options as any).nitro || {}) as NitroConfig - const nitroConfig: NitroConfig = defu(_nitroConfig, { + const nitroConfig: NitroConfig = defu(_nitroConfig, { rootDir: nuxt.options.rootDir, workspaceDir: nuxt.options.workspaceDir, srcDir: join(nuxt.options.srcDir, 'server'), @@ -65,10 +65,10 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) { ...(nuxt.options.dev ? [] : [ - ...nuxt.options.experimental.externalVue ? [] : ['vue', '@vue/'], - '@nuxt/', - nuxt.options.buildDir - ]), + ...nuxt.options.experimental.externalVue ? [] : ['vue', '@vue/'], + '@nuxt/', + nuxt.options.buildDir + ]), 'nuxt/dist', 'nuxt3/dist', distDir @@ -79,10 +79,10 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) { ? {} : { - 'vue/compiler-sfc': 'vue/compiler-sfc', - 'vue/server-renderer': 'vue/server-renderer', - vue: await resolvePath(`vue/dist/vue.cjs${nuxt.options.dev ? '' : '.prod'}.js`) - }, + 'vue/compiler-sfc': 'vue/compiler-sfc', + 'vue/server-renderer': 'vue/server-renderer', + vue: await resolvePath(`vue/dist/vue.cjs${nuxt.options.dev ? '' : '.prod'}.js`) + }, // Vue 3 mocks 'estree-walker': 'unenv/runtime/mock/proxy', '@babel/parser': 'unenv/runtime/mock/proxy', From 72d9f30849b2850bba440fb2b533a309cab64ca2 Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Fri, 30 Sep 2022 21:38:29 +0100 Subject: [PATCH 3/4] test: add fixture --- test/basic.test.ts | 6 ++++++ test/fixtures/basic/nuxt.config.ts | 3 +++ test/fixtures/basic/pages/route-rules/spa.vue | 5 +++++ 3 files changed, 14 insertions(+) create mode 100644 test/fixtures/basic/pages/route-rules/spa.vue diff --git a/test/basic.test.ts b/test/basic.test.ts index 2fe9c019dba..b88b3e7d81d 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -29,6 +29,12 @@ describe('server api', () => { }) }) +describe('route rules', () => { + it('should enable spa mode', async () => { + expect(await $fetch('/route-rules/spa')).toContain('serverRendered:false') + }) +}) + describe('pages', () => { it('render index', async () => { const html = await $fetch('/') diff --git a/test/fixtures/basic/nuxt.config.ts b/test/fixtures/basic/nuxt.config.ts index f95ce54fbd0..0ba482c7054 100644 --- a/test/fixtures/basic/nuxt.config.ts +++ b/test/fixtures/basic/nuxt.config.ts @@ -17,6 +17,9 @@ export default defineNuxtConfig({ './extends/node_modules/foo' ], nitro: { + routes: { + '/route-rules/spa': { ssr: false } + }, output: { dir: process.env.NITRO_OUTPUT_DIR }, prerender: { routes: [ diff --git a/test/fixtures/basic/pages/route-rules/spa.vue b/test/fixtures/basic/pages/route-rules/spa.vue new file mode 100644 index 00000000000..6777da5c537 --- /dev/null +++ b/test/fixtures/basic/pages/route-rules/spa.vue @@ -0,0 +1,5 @@ + From 3373ba30d2b1cf1c9a6db14a40e75cba445cfb0d Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Tue, 11 Oct 2022 15:18:49 +0100 Subject: [PATCH 4/4] feat: share route options from newer nitro versions --- packages/nuxt/src/core/runtime/nitro/renderer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nuxt/src/core/runtime/nitro/renderer.ts b/packages/nuxt/src/core/runtime/nitro/renderer.ts index 8b34c50ec52..8567b162f4b 100644 --- a/packages/nuxt/src/core/runtime/nitro/renderer.ts +++ b/packages/nuxt/src/core/runtime/nitro/renderer.ts @@ -133,7 +133,7 @@ export default defineRenderHandler(async (event) => { } // TODO: share across endpoints on event context - const routeOptions = routerOptions.lookup(url) || {} + const routeOptions = event.context.routeOptions || routerOptions.lookup(url) || {} // Initialize ssr context const ssrContext: NuxtSSRContext = {