Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: hydration miss match for prerender #1733

Merged
merged 4 commits into from
Dec 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions specs/fixtures/issues/1721/app.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<template>
<div>
<h1>{{ $t('welcome') }}</h1>
<p>Current locale: {{ locale }}</p>
<ul>
<li
v-for="({ code, name }, i) in locales"
:key="code"
:class="{ 'selected': code === locale }"
@click.prevent="setLocale(code)"
>
{{ name }}
</li>
</ul>
</div>
</template>

<script setup>
const { locale, locales, setLocale } = useI18n();
</script>

<style>
/* underline style for selected locale */
.selected {
text-decoration: underline;
}

ul {
list-style: none;
padding: 0;
display: flex;
font-size: larger;
}
li {
margin-right: 1rem;
cursor: pointer;
}
</style>
44 changes: 44 additions & 0 deletions specs/fixtures/issues/1721/nuxt.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
modules: ['@nuxtjs/i18n'],

i18n: {
strategy: 'no_prefix',
detectBrowserLanguage: {
useCookie: true,
cookieKey: 'i18n_redirected',
redirectOn: 'root'
},
defaultLocale: 'en',
locales: [
{
code: 'en',
name: 'EN'
},
{
code: 'fr',
name: 'FR'
},
{
code: 'es',
name: 'ES'
}
],
vueI18n: {
legacy: false,
locale: 'en',
fallbackLocale: ['en'],
messages: {
en: {
welcome: 'Welcome'
},
fr: {
welcome: 'Bienvenue'
},
es: {
welcome: 'Bienvenido'
}
}
}
}
})
13 changes: 13 additions & 0 deletions specs/fixtures/issues/1721/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"private": true,
"scripts": {
"build": "nuxt build",
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview"
},
"devDependencies": {
"@nuxtjs/i18n": "latest",
"nuxt": "latest"
}
}
20 changes: 20 additions & 0 deletions specs/issues/1721.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { test, describe } from 'vitest'
import { fileURLToPath } from 'node:url'
import { setup } from '@nuxt/test-utils'

describe.skip('#1721', async () => {
await setup({
rootDir: fileURLToPath(new URL(`../fixtures/issues/1721`, import.meta.url)),
browser: true,
// overrides
nuxtConfig: {
_generate: true
}
})

test('should be occured hydrate miss match', async () => {
// TODO:
// if @nuxt/test-utils supports prerender build testing, we can test it.
//
})
})
12 changes: 9 additions & 3 deletions src/gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ export function generateLoaderOptions(
langDir: NuxtI18nOptions['langDir'],
localesRelativeBase: string,
options: LoaderOptions = {},
dev = true
misc: {
dev: boolean
ssg: boolean
ssr: boolean
} = { dev: true, ssg: false, ssr: true }
) {
let genCode = ''
const localeInfo = options.localeInfo || []
Expand Down Expand Up @@ -68,7 +72,7 @@ export function generateLoaderOptions(
if (key === 'vueI18n') {
const optionLoaderVariable = `${key}OptionsLoader`
genCodes += ` const ${optionLoaderVariable} = ${isObject(value)
? `async (context) => ${generateVueI18nOptions(value, dev)}\n`
? `async (context) => ${generateVueI18nOptions(value, misc.dev)}\n`
: isString(value)
? `async (context) => import(${toCode(value)}).then(r => (r.default || r)(context))\n`
: `async (context) => ${toCode({})}\n`
Expand Down Expand Up @@ -112,13 +116,15 @@ export function generateLoaderOptions(
codes += `}\n`
return codes
} else if (rootKey === 'additionalMessages') {
return `export const ${rootKey} = ${generateAdditionalMessages(rootValue, dev)}\n`
return `export const ${rootKey} = ${generateAdditionalMessages(rootValue, misc.dev)}\n`
} else {
return `export const ${rootKey} = ${toCode(rootValue)}\n`
}
}).join('\n')}`

genCode += `export const NUXT_I18N_MODULE_ID = ${toCode(NUXT_I18N_MODULE_ID)}\n`
genCode += `export const isSSG = ${toCode(misc.ssg)}\n`
genCode += `export const isSSR = ${toCode(misc.ssr)}\n`

debug('generate code', genCode)
return genCode
Expand Down
6 changes: 5 additions & 1 deletion src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,11 @@ export default defineNuxtModule<NuxtI18nOptions>({
__normalizedLocales: normalizedLocales
}
},
nuxt.options.dev
{
ssg: nuxt.options._generate,
ssr: nuxt.options.ssr,
dev: nuxt.options.dev
}
)
}
})
Expand Down
2 changes: 2 additions & 0 deletions src/options.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ export const nuxtI18nOptions: DeepRequired<NuxtI18nOptions> = {}
export const nuxtI18nOptionsDefault: NuxtI18nOptionsDefault = {}
export const nuxtI18nInternalOptions: DeepRequired<NuxtI18nInternalOptions> = {}
export const NUXT_I18N_MODULE_ID = ''
export const isSSG = false
export const isSSR = false

export {
NuxtI18nOptions,
Expand Down
24 changes: 22 additions & 2 deletions src/runtime/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import {
nuxtI18nOptionsDefault,
localeMessages,
additionalMessages,
NUXT_I18N_MODULE_ID
NUXT_I18N_MODULE_ID,
isSSG
} from '#build/i18n.options.mjs'

import type { NuxtApp } from '#imports'
Expand Down Expand Up @@ -256,22 +257,37 @@ export type DetectBrowserLanguageNotDetectReason =
| 'not_found_match'
| 'not_redirect_on_root'
| 'not_redirect_on_no_prefix'
| 'detect_ignore_on_ssg'
export type DetectBrowserLanguageFrom = 'unknown' | 'cookie' | 'navigator_or_header' | 'fallback'
export type DetectBrowserLanguageFromResult = {
locale: string
stat: boolean
reason?: DetectBrowserLanguageNotDetectReason
from?: DetectBrowserLanguageFrom
}
export type DetectLocaleForSSGStatus = 'ssg_ignore' | 'ssg_setup' | 'normal'

export const DefaultDetectBrowserLanguageFromResult: DetectBrowserLanguageFromResult = {
locale: '',
stat: false,
reason: 'unknown',
from: 'unknown'
}

export function detectBrowserLanguage<Context extends NuxtApp = NuxtApp>(
route: string | Route | RouteLocationNormalized | RouteLocationNormalizedLoaded,
context: any,
nuxtI18nOptions: DeepRequired<NuxtI18nOptions<Context>>,
nuxtI18nInternalOptions: DeepRequired<NuxtI18nInternalOptions>,
localeCodes: string[] = [],
locale: Locale = ''
locale: Locale = '',
mode: DetectLocaleForSSGStatus
): DetectBrowserLanguageFromResult {
// browser detection is ignored if it's a nuxt generate.
if (isSSG && (process.server || mode === 'ssg_ignore')) {
return { locale: '', stat: true, reason: 'detect_ignore_on_ssg' }
}

const { strategy } = nuxtI18nOptions
const { redirectOn, alwaysRedirect, useCookie, fallbackLocale } =
nuxtI18nOptions.detectBrowserLanguage as DetectBrowserLanguageOptions
Expand Down Expand Up @@ -356,6 +372,10 @@ export function detectBrowserLanguage<Context extends NuxtApp = NuxtApp>(
}
}

if (mode === 'ssg_setup' && finalLocale) {
return { locale: finalLocale, stat: true, from: localeFrom }
}

return { locale: '', stat: false, reason: 'not_found_match' }
}

Expand Down
Loading