From 7ccaf16051272c27344548f1c5608a545595ef83 Mon Sep 17 00:00:00 2001 From: Bobbie Goede Date: Thu, 5 Sep 2024 06:13:29 +0200 Subject: [PATCH] fix: cookie being reset on reload in ssg build (#3087) * fix: cookie being reset on reload in ssg build * test: assert ssg cookie not being reset --- specs/ssg/no_prefix.spec.ts | 45 +++++++++++++++++++++++++++++++++++++ specs/utils/context.ts | 2 +- specs/utils/nuxt.ts | 8 +++---- specs/utils/server.ts | 25 +++++++++------------ src/runtime/plugins/i18n.ts | 3 ++- 5 files changed, 62 insertions(+), 21 deletions(-) create mode 100644 specs/ssg/no_prefix.spec.ts diff --git a/specs/ssg/no_prefix.spec.ts b/specs/ssg/no_prefix.spec.ts new file mode 100644 index 000000000..bb2e1ac20 --- /dev/null +++ b/specs/ssg/no_prefix.spec.ts @@ -0,0 +1,45 @@ +import { test, expect } from 'vitest' +import { fileURLToPath } from 'node:url' +import { setup } from '../utils' +import { getText, gotoPath, renderPage, startServerWithRuntimeConfig, waitForURL } from '../helper' + +await setup({ + rootDir: fileURLToPath(new URL(`../fixtures/basic`, import.meta.url)), + browser: true, + prerender: true, + // overrides + nuxtConfig: { + i18n: { + debug: true, + strategy: 'no_prefix', + detectBrowserLanguage: { + useCookie: true, + cookieKey: 'my_custom_cookie_name', + redirectOn: 'root', + cookieCrossOrigin: true, + cookieSecure: true + } + } + } +}) + +test('does not reset cookie no refresh', async () => { + const { page } = await renderPage('/', { locale: 'en' }) + const ctx = await page.context() + expect(await ctx.cookies()).toMatchObject([ + { name: 'my_custom_cookie_name', value: 'en', secure: true, sameSite: 'None' } + ]) + + // click `fr` lang switch link + await page.locator('#set-locale-link-fr').click() + expect(await ctx.cookies()).toMatchObject([ + { name: 'my_custom_cookie_name', value: 'fr', secure: true, sameSite: 'None' } + ]) + + await page.reload() + await waitForURL(page, '/') + + expect(await ctx.cookies()).toMatchObject([ + { name: 'my_custom_cookie_name', value: 'fr', secure: true, sameSite: 'None' } + ]) +}) diff --git a/specs/utils/context.ts b/specs/utils/context.ts index 0c94a989e..73ff5cf0c 100644 --- a/specs/utils/context.ts +++ b/specs/utils/context.ts @@ -11,7 +11,7 @@ export function createTestContext(options: Partial): TestContext { configFile: 'nuxt.config', setupTimeout: 120 * 1000, dev: !!JSON.parse(process.env.NUXT_TEST_DEV || 'false'), - prerender: false, + prerender: options.prerender ?? false, logLevel: 1, server: true, build: options.browser !== false || options.server !== false, diff --git a/specs/utils/nuxt.ts b/specs/utils/nuxt.ts index ad27439e0..f77af8dad 100644 --- a/specs/utils/nuxt.ts +++ b/specs/utils/nuxt.ts @@ -59,17 +59,17 @@ export async function loadFixture(testContext: VitestContext) { let testKey = getTestKey(testContext) const buildDir = resolve(ctx.options.rootDir, '.nuxt', testKey) - const outputDir = ctx.options.prerender - ? resolve(buildDir, 'output', testKey) - : resolve(rootDir, '.output', testKey) + const outputDir = resolve(ctx.options.rootDir, '.output', testKey) ctx.options.nuxtConfig = defu(ctx.options.nuxtConfig, { buildDir, // NOTE: the following code is added for prerender _generate: ctx.options.prerender, nitro: { + ...(ctx.options.prerender ? { static: true } : {}), output: { - dir: outputDir + dir: outputDir, + ...(ctx.options.prerender ? { publicDir: outputDir + '/public' } : {}) } } }) diff --git a/specs/utils/server.ts b/specs/utils/server.ts index 23977cb91..6d04af6e3 100644 --- a/specs/utils/server.ts +++ b/specs/utils/server.ts @@ -49,28 +49,23 @@ export async function startServer(env: Record = {}) { ctx.serverProcess.kill() throw lastError || new Error('Timeout waiting for dev server!') } else if (ctx.options.prerender) { - const command = `npx serve -s ./dist -p ${port}` + const command = `npx serve -s ${ctx.nuxt!.options.nitro!.output?.publicDir} -l tcp://${host}:${port} --no-port-switching` + // ; (await import('consola')).consola.restoreConsole() const [_command, ...commandArgs] = command.split(' ') + ctx.serverProcess = execa(_command, commandArgs, { - cwd: ctx.nuxt!.options.rootDir, + //@ts-ignore env: { + ...process.env, + PORT: String(port), + HOST: host, ...env } - // stdio: 'inherit' }) - await waitForPort(port, { retries: 32 }) - for (let i = 0; i < 50; i++) { - await new Promise(resolve => setTimeout(resolve, 100)) - try { - const res = await $fetch(ctx.nuxt!.options.app.baseURL) - if (!res.includes('__NUXT_LOADING__')) { - return - } - } catch {} - } - ctx.serverProcess.kill() - throw new Error('Timeout waiting for ssg preview!') + + await waitForPort(port, { retries: 32, host, delay: 1000 }) } else { + //@ts-ignore ctx.serverProcess = execa('node', [resolve(ctx.nuxt!.options.nitro.output!.dir!, 'server/index.mjs')], { stdio: 'inherit', env: { diff --git a/src/runtime/plugins/i18n.ts b/src/runtime/plugins/i18n.ts index a1f280ec7..7838c7e21 100644 --- a/src/runtime/plugins/i18n.ts +++ b/src/runtime/plugins/i18n.ts @@ -159,6 +159,7 @@ export default defineNuxtPlugin({ * avoid hydration mismatch for SSG mode */ if (isSSGModeInitialSetup() && runtimeI18n.strategy === 'no_prefix' && import.meta.client) { + const initialLocaleCookie = localeCookie.value nuxt.hook('app:mounted', () => { __DEBUG__ && console.log('hook app:mounted') const detected = detectBrowserLanguage( @@ -167,7 +168,7 @@ export default defineNuxtPlugin({ ssg: 'ssg_setup', callType: 'setup', firstAccess: true, - localeCookie: _getLocaleCookie(localeCookie, _detectBrowserLanguage, runtimeI18n.defaultLocale) + localeCookie: initialLocaleCookie }, initialLocale )