fix(next): properly instantiates locale context (#10451)
Currently, unless a locale is present in the URL search params, the locale context is instantiated using the default locale until prefs load in client-side. This causes the locale selector to briefly render in with the incorrect (default) locale before being replaced by the proper locale of the request. For example, if the default locale is `en`, and the page is requested in `es`, the locale selector will flash with English before changing to the correct locale, even though the page data itself is properly loaded in Spanish. This is especially evident within slow networks. The fix is to query the user's locale preference server-side and thread it into the locale provider to initialize state. Because search params are not available within server layouts, we cannot pass the locale param in the same way, so we rely on the provider itself to read them from the `useSearchParams` hook. If present, this takes precedence over the user's preference if it exists. Since the root page also queries the user's locale preference to determine the proper locale across navigation, we use React's cache function to dedupe these function calls and ensure only a single query is made to the db for each request.
This commit is contained in:
@@ -10,6 +10,7 @@ import React from 'react'
|
|||||||
|
|
||||||
import { getNavPrefs } from '../../elements/Nav/getNavPrefs.js'
|
import { getNavPrefs } from '../../elements/Nav/getNavPrefs.js'
|
||||||
import { getRequestLanguage } from '../../utilities/getRequestLanguage.js'
|
import { getRequestLanguage } from '../../utilities/getRequestLanguage.js'
|
||||||
|
import { getRequestLocale } from '../../utilities/getRequestLocale.js'
|
||||||
import { getRequestTheme } from '../../utilities/getRequestTheme.js'
|
import { getRequestTheme } from '../../utilities/getRequestTheme.js'
|
||||||
import { initReq } from '../../utilities/initReq.js'
|
import { initReq } from '../../utilities/initReq.js'
|
||||||
import { checkDependencies } from './checkDependencies.js'
|
import { checkDependencies } from './checkDependencies.js'
|
||||||
@@ -92,6 +93,11 @@ export const RootLayout = async ({
|
|||||||
importMap,
|
importMap,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const locale = await getRequestLocale({
|
||||||
|
payload,
|
||||||
|
user,
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<html
|
<html
|
||||||
data-theme={theme}
|
data-theme={theme}
|
||||||
@@ -110,6 +116,7 @@ export const RootLayout = async ({
|
|||||||
isNavOpen={navPrefs?.open ?? true}
|
isNavOpen={navPrefs?.open ?? true}
|
||||||
languageCode={languageCode}
|
languageCode={languageCode}
|
||||||
languageOptions={languageOptions}
|
languageOptions={languageOptions}
|
||||||
|
locale={locale?.code}
|
||||||
permissions={permissions}
|
permissions={permissions}
|
||||||
serverFunction={serverFunction}
|
serverFunction={serverFunction}
|
||||||
switchLanguageServerAction={switchLanguageServerAction}
|
switchLanguageServerAction={switchLanguageServerAction}
|
||||||
|
|||||||
41
packages/next/src/utilities/getPreference.ts
Normal file
41
packages/next/src/utilities/getPreference.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import type { Payload, User } from 'payload'
|
||||||
|
|
||||||
|
import { cache } from 'react'
|
||||||
|
|
||||||
|
export const getPreference = cache(
|
||||||
|
async <T>(key: string, payload: Payload, user: User): Promise<T> => {
|
||||||
|
let result: T = null
|
||||||
|
|
||||||
|
try {
|
||||||
|
result = await payload
|
||||||
|
.find({
|
||||||
|
collection: 'payload-preferences',
|
||||||
|
depth: 0,
|
||||||
|
limit: 1,
|
||||||
|
user,
|
||||||
|
where: {
|
||||||
|
and: [
|
||||||
|
{
|
||||||
|
'user.relationTo': {
|
||||||
|
equals: payload.config.admin.user,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'user.value': {
|
||||||
|
equals: user.id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: {
|
||||||
|
equals: key,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
?.then((res) => res.docs?.[0]?.value as T)
|
||||||
|
} catch (_err) {} // eslint-disable-line no-empty
|
||||||
|
|
||||||
|
return result
|
||||||
|
},
|
||||||
|
)
|
||||||
32
packages/next/src/utilities/getRequestLocale.ts
Normal file
32
packages/next/src/utilities/getRequestLocale.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import type { Locale, Payload, User } from 'payload'
|
||||||
|
|
||||||
|
import { findLocaleFromCode } from '@payloadcms/ui/shared'
|
||||||
|
|
||||||
|
import { getPreference } from './getPreference.js'
|
||||||
|
|
||||||
|
type GetRequestLocalesArgs = {
|
||||||
|
localeFromParams?: string
|
||||||
|
payload: Payload
|
||||||
|
user: User
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getRequestLocale({
|
||||||
|
localeFromParams,
|
||||||
|
payload,
|
||||||
|
user,
|
||||||
|
}: GetRequestLocalesArgs): Promise<Locale> {
|
||||||
|
if (payload.config.localization) {
|
||||||
|
return (
|
||||||
|
findLocaleFromCode(
|
||||||
|
payload.config.localization,
|
||||||
|
localeFromParams || (await getPreference<Locale['code']>('locale', payload, user)),
|
||||||
|
) ||
|
||||||
|
findLocaleFromCode(
|
||||||
|
payload.config.localization,
|
||||||
|
payload.config.localization.defaultLocale || 'en',
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
import type { Payload } from 'payload'
|
|
||||||
|
|
||||||
import { sanitizeFallbackLocale } from 'payload'
|
|
||||||
|
|
||||||
type GetRequestLocalesArgs = {
|
|
||||||
data?: Record<string, any>
|
|
||||||
localization: Exclude<Payload['config']['localization'], false>
|
|
||||||
searchParams?: URLSearchParams
|
|
||||||
}
|
|
||||||
export function getRequestLocales({ data, localization, searchParams }: GetRequestLocalesArgs): {
|
|
||||||
fallbackLocale: string
|
|
||||||
locale: string
|
|
||||||
} {
|
|
||||||
let locale = searchParams.get('locale')
|
|
||||||
let fallbackLocale = searchParams.get('fallback-locale') || searchParams.get('fallbackLocale')
|
|
||||||
|
|
||||||
if (data) {
|
|
||||||
if (data?.locale) {
|
|
||||||
locale = data.locale
|
|
||||||
}
|
|
||||||
if (data?.['fallback-locale']) {
|
|
||||||
fallbackLocale = data['fallback-locale']
|
|
||||||
}
|
|
||||||
if (data?.['fallbackLocale']) {
|
|
||||||
fallbackLocale = data['fallbackLocale']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fallbackLocale = sanitizeFallbackLocale({
|
|
||||||
fallbackLocale,
|
|
||||||
locale,
|
|
||||||
localization,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (locale === '*') {
|
|
||||||
locale = 'all'
|
|
||||||
} else if (!localization.localeCodes.includes(locale)) {
|
|
||||||
locale = localization.defaultLocale
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
fallbackLocale,
|
|
||||||
locale,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
import type { I18n } from '@payloadcms/translations'
|
import type { I18n } from '@payloadcms/translations'
|
||||||
import type { InitPageResult, Locale, VisibleEntities } from 'payload'
|
import type { InitPageResult, VisibleEntities } from 'payload'
|
||||||
|
|
||||||
import { findLocaleFromCode } from '@payloadcms/ui/shared'
|
|
||||||
import { headers as getHeaders } from 'next/headers.js'
|
import { headers as getHeaders } from 'next/headers.js'
|
||||||
import { notFound } from 'next/navigation.js'
|
import { notFound } from 'next/navigation.js'
|
||||||
import { createLocalReq, getPayload, isEntityHidden, parseCookies } from 'payload'
|
import { createLocalReq, getPayload, isEntityHidden, parseCookies } from 'payload'
|
||||||
@@ -9,6 +8,7 @@ import * as qs from 'qs-esm'
|
|||||||
|
|
||||||
import type { Args } from './types.js'
|
import type { Args } from './types.js'
|
||||||
|
|
||||||
|
import { getRequestLocale } from '../getRequestLocale.js'
|
||||||
import { initReq } from '../initReq.js'
|
import { initReq } from '../initReq.js'
|
||||||
import { getRouteInfo } from './handleAdminPage.js'
|
import { getRouteInfo } from './handleAdminPage.js'
|
||||||
import { handleAuthRedirect } from './handleAuthRedirect.js'
|
import { handleAuthRedirect } from './handleAuthRedirect.js'
|
||||||
@@ -28,7 +28,6 @@ export const initPage = async ({
|
|||||||
const {
|
const {
|
||||||
collections,
|
collections,
|
||||||
globals,
|
globals,
|
||||||
localization,
|
|
||||||
routes: { admin: adminRoute },
|
routes: { admin: adminRoute },
|
||||||
} = payload.config
|
} = payload.config
|
||||||
|
|
||||||
@@ -74,52 +73,13 @@ export const initPage = async ({
|
|||||||
|
|
||||||
req.user = user
|
req.user = user
|
||||||
|
|
||||||
const localeParam = searchParams?.locale as string
|
const locale = await getRequestLocale({
|
||||||
let locale: Locale
|
localeFromParams: req.query.locale as string,
|
||||||
|
payload,
|
||||||
|
user,
|
||||||
|
})
|
||||||
|
|
||||||
if (localization) {
|
req.locale = locale?.code
|
||||||
const defaultLocaleCode = localization.defaultLocale ? localization.defaultLocale : 'en'
|
|
||||||
let localeCode: string = localeParam
|
|
||||||
|
|
||||||
if (!localeCode) {
|
|
||||||
try {
|
|
||||||
localeCode = await payload
|
|
||||||
.find({
|
|
||||||
collection: 'payload-preferences',
|
|
||||||
depth: 0,
|
|
||||||
limit: 1,
|
|
||||||
user,
|
|
||||||
where: {
|
|
||||||
and: [
|
|
||||||
{
|
|
||||||
'user.relationTo': {
|
|
||||||
equals: payload.config.admin.user,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'user.value': {
|
|
||||||
equals: user.id,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: {
|
|
||||||
equals: 'locale',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
})
|
|
||||||
?.then((res) => res.docs?.[0]?.value as string)
|
|
||||||
} catch (_err) {} // eslint-disable-line no-empty
|
|
||||||
}
|
|
||||||
|
|
||||||
locale = findLocaleFromCode(localization, localeCode)
|
|
||||||
|
|
||||||
if (!locale) {
|
|
||||||
locale = findLocaleFromCode(localization, defaultLocaleCode)
|
|
||||||
}
|
|
||||||
req.locale = locale.code
|
|
||||||
}
|
|
||||||
|
|
||||||
const visibleEntities: VisibleEntities = {
|
const visibleEntities: VisibleEntities = {
|
||||||
collections: collections
|
collections: collections
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ export const RootPage = async ({
|
|||||||
} = config
|
} = config
|
||||||
|
|
||||||
const params = await paramsPromise
|
const params = await paramsPromise
|
||||||
|
|
||||||
const currentRoute = formatAdminURL({
|
const currentRoute = formatAdminURL({
|
||||||
adminRoute,
|
adminRoute,
|
||||||
path: `${Array.isArray(params.segments) ? `/${params.segments.join('/')}` : ''}`,
|
path: `${Array.isArray(params.segments) ? `/${params.segments.join('/')}` : ''}`,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export const updateHandler: PayloadHandler = async (incomingReq) => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
data = await incomingReq.json()
|
data = await incomingReq.json()
|
||||||
} catch (error) {
|
} catch (_err) {
|
||||||
data = {}
|
data = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,20 +12,24 @@ import { usePreferences } from '../Preferences/index.js'
|
|||||||
|
|
||||||
const LocaleContext = createContext({} as Locale)
|
const LocaleContext = createContext({} as Locale)
|
||||||
|
|
||||||
export const LocaleProvider: React.FC<{ children?: React.ReactNode }> = ({ children }) => {
|
export const LocaleProvider: React.FC<{ children?: React.ReactNode; locale?: Locale['code'] }> = ({
|
||||||
|
children,
|
||||||
|
locale: localeFromProps,
|
||||||
|
}) => {
|
||||||
const {
|
const {
|
||||||
config: { localization = false },
|
config: { localization = false },
|
||||||
} = useConfig()
|
} = useConfig()
|
||||||
|
|
||||||
const { user } = useAuth()
|
const { user } = useAuth()
|
||||||
|
|
||||||
const defaultLocale =
|
const defaultLocale =
|
||||||
localization && localization.defaultLocale ? localization.defaultLocale : 'en'
|
localization && localization.defaultLocale ? localization.defaultLocale : 'en'
|
||||||
|
|
||||||
const { getPreference, setPreference } = usePreferences()
|
const { getPreference, setPreference } = usePreferences()
|
||||||
const searchParams = useSearchParams()
|
const localeFromParams = useSearchParams().get('locale')
|
||||||
const localeFromParams = searchParams.get('locale')
|
|
||||||
|
|
||||||
const [localeCode, setLocaleCode] = useState<string>(defaultLocale)
|
// `localeFromProps` originates from the root layout, which does not have access to search params
|
||||||
|
const [localeCode, setLocaleCode] = useState<string>(localeFromProps || localeFromParams)
|
||||||
|
|
||||||
const locale: Locale = React.useMemo(() => {
|
const locale: Locale = React.useMemo(() => {
|
||||||
if (!localization) {
|
if (!localization) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import type { I18nClient, Language } from '@payloadcms/translations'
|
|||||||
import type {
|
import type {
|
||||||
ClientConfig,
|
ClientConfig,
|
||||||
LanguageOptions,
|
LanguageOptions,
|
||||||
|
Locale,
|
||||||
SanitizedPermissions,
|
SanitizedPermissions,
|
||||||
ServerFunctionClient,
|
ServerFunctionClient,
|
||||||
User,
|
User,
|
||||||
@@ -41,6 +42,7 @@ type Props = {
|
|||||||
readonly isNavOpen?: boolean
|
readonly isNavOpen?: boolean
|
||||||
readonly languageCode: string
|
readonly languageCode: string
|
||||||
readonly languageOptions: LanguageOptions
|
readonly languageOptions: LanguageOptions
|
||||||
|
readonly locale?: Locale['code']
|
||||||
readonly permissions: SanitizedPermissions
|
readonly permissions: SanitizedPermissions
|
||||||
readonly serverFunction: ServerFunctionClient
|
readonly serverFunction: ServerFunctionClient
|
||||||
readonly switchLanguageServerAction?: (lang: string) => Promise<void>
|
readonly switchLanguageServerAction?: (lang: string) => Promise<void>
|
||||||
@@ -57,6 +59,7 @@ export const RootProvider: React.FC<Props> = ({
|
|||||||
isNavOpen,
|
isNavOpen,
|
||||||
languageCode,
|
languageCode,
|
||||||
languageOptions,
|
languageOptions,
|
||||||
|
locale,
|
||||||
permissions,
|
permissions,
|
||||||
serverFunction,
|
serverFunction,
|
||||||
switchLanguageServerAction,
|
switchLanguageServerAction,
|
||||||
@@ -96,7 +99,7 @@ export const RootProvider: React.FC<Props> = ({
|
|||||||
<PreferencesProvider>
|
<PreferencesProvider>
|
||||||
<ThemeProvider theme={theme}>
|
<ThemeProvider theme={theme}>
|
||||||
<ParamsProvider>
|
<ParamsProvider>
|
||||||
<LocaleProvider>
|
<LocaleProvider locale={locale}>
|
||||||
<StepNavProvider>
|
<StepNavProvider>
|
||||||
<LoadingOverlayProvider>
|
<LoadingOverlayProvider>
|
||||||
<DocumentEventsProvider>
|
<DocumentEventsProvider>
|
||||||
|
|||||||
@@ -168,6 +168,7 @@ describe('Text', () => {
|
|||||||
await upsertPrefs<Config, GeneratedTypes<any>>({
|
await upsertPrefs<Config, GeneratedTypes<any>>({
|
||||||
payload,
|
payload,
|
||||||
user: client.user,
|
user: client.user,
|
||||||
|
key: 'text-fields-list',
|
||||||
value: {
|
value: {
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,51 +9,65 @@ export const upsertPrefs = async <
|
|||||||
payload,
|
payload,
|
||||||
user,
|
user,
|
||||||
value,
|
value,
|
||||||
|
key,
|
||||||
}: {
|
}: {
|
||||||
|
key: string
|
||||||
payload: PayloadTestSDK<TConfig>
|
payload: PayloadTestSDK<TConfig>
|
||||||
user: TypedUser
|
user: TypedUser
|
||||||
value: Record<string, any>
|
value: any
|
||||||
}): Promise<TGeneratedTypes['collections']['payload-preferences']> => {
|
}): Promise<TGeneratedTypes['collections']['payload-preferences']> => {
|
||||||
let prefs = await payload
|
try {
|
||||||
.find({
|
let prefs = await payload
|
||||||
collection: 'payload-preferences',
|
.find({
|
||||||
depth: 0,
|
collection: 'payload-preferences',
|
||||||
limit: 1,
|
depth: 0,
|
||||||
where: {
|
limit: 1,
|
||||||
and: [
|
where: {
|
||||||
{ key: { equals: 'text-fields-list' } },
|
and: [
|
||||||
{ 'user.value': { equals: user.id } },
|
{ key: { equals: key } },
|
||||||
{ 'user.relationTo': { equals: user.collection } },
|
{ 'user.value': { equals: user.id } },
|
||||||
],
|
{ 'user.relationTo': { equals: user.collection } },
|
||||||
},
|
],
|
||||||
})
|
},
|
||||||
?.then((res) => res.docs?.[0])
|
})
|
||||||
|
?.then((res) => res.docs?.[0])
|
||||||
|
|
||||||
if (!prefs) {
|
if (!prefs) {
|
||||||
prefs = await payload.create({
|
prefs = await payload.create({
|
||||||
collection: 'payload-preferences',
|
collection: 'payload-preferences',
|
||||||
depth: 0,
|
depth: 0,
|
||||||
data: {
|
data: {
|
||||||
key: 'text-fields-list',
|
key,
|
||||||
user: {
|
user: {
|
||||||
relationTo: user.collection,
|
relationTo: user.collection,
|
||||||
value: user.id,
|
value: user.id,
|
||||||
|
},
|
||||||
|
value,
|
||||||
},
|
},
|
||||||
value,
|
})
|
||||||
},
|
} else {
|
||||||
})
|
const newValue = typeof value === 'object' ? { ...(prefs?.value || {}), ...value } : value
|
||||||
} else {
|
|
||||||
prefs = await payload.update({
|
prefs = await payload.update({
|
||||||
collection: 'payload-preferences',
|
collection: 'payload-preferences',
|
||||||
id: prefs.id,
|
id: prefs.id,
|
||||||
data: {
|
data: {
|
||||||
value: {
|
key,
|
||||||
...(prefs?.value ?? {}),
|
user: {
|
||||||
...value,
|
collection: user.collection,
|
||||||
|
value: user.id,
|
||||||
|
},
|
||||||
|
value: newValue,
|
||||||
},
|
},
|
||||||
},
|
})
|
||||||
})
|
|
||||||
|
if (prefs?.status >= 400) {
|
||||||
|
throw new Error(prefs.data?.errors?.[0]?.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
return prefs
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error upserting prefs', e)
|
||||||
}
|
}
|
||||||
|
|
||||||
return prefs
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,9 @@ import {
|
|||||||
withRequiredLocalizedFields,
|
withRequiredLocalizedFields,
|
||||||
} from './shared.js'
|
} from './shared.js'
|
||||||
import { navigateToDoc } from 'helpers/e2e/navigateToDoc.js'
|
import { navigateToDoc } from 'helpers/e2e/navigateToDoc.js'
|
||||||
|
import { upsertPrefs } from 'helpers/e2e/upsertPrefs.js'
|
||||||
|
import { RESTClient } from 'helpers/rest.js'
|
||||||
|
import { GeneratedTypes } from 'helpers/sdk/types.js'
|
||||||
const filename = fileURLToPath(import.meta.url)
|
const filename = fileURLToPath(import.meta.url)
|
||||||
const dirname = path.dirname(filename)
|
const dirname = path.dirname(filename)
|
||||||
|
|
||||||
@@ -54,6 +57,7 @@ const description = 'description'
|
|||||||
|
|
||||||
let page: Page
|
let page: Page
|
||||||
let payload: PayloadTestSDK<Config>
|
let payload: PayloadTestSDK<Config>
|
||||||
|
let client: RESTClient
|
||||||
let serverURL: string
|
let serverURL: string
|
||||||
let richTextURL: AdminUrlUtil
|
let richTextURL: AdminUrlUtil
|
||||||
let context: BrowserContext
|
let context: BrowserContext
|
||||||
@@ -73,6 +77,9 @@ describe('Localization', () => {
|
|||||||
|
|
||||||
initPageConsoleErrorCatch(page)
|
initPageConsoleErrorCatch(page)
|
||||||
|
|
||||||
|
client = new RESTClient(null, { defaultSlug: 'users', serverURL })
|
||||||
|
await client.login()
|
||||||
|
|
||||||
await ensureCompilationIsDone({ page, serverURL })
|
await ensureCompilationIsDone({ page, serverURL })
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -84,8 +91,30 @@ describe('Localization', () => {
|
|||||||
// })
|
// })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('localizer', async () => {
|
||||||
|
test('should not render default locale in locale selector when prefs are not default', async () => {
|
||||||
|
// change prefs to spanish, then load page and check that the localizer label does not say English
|
||||||
|
await upsertPrefs<Config, GeneratedTypes<any>>({
|
||||||
|
payload,
|
||||||
|
user: client.user,
|
||||||
|
key: 'locale',
|
||||||
|
value: 'es',
|
||||||
|
})
|
||||||
|
|
||||||
|
await page.goto(url.list)
|
||||||
|
|
||||||
|
const localeLabel = await page
|
||||||
|
.locator('.localizer.app-header__localizer .localizer-button__current-label')
|
||||||
|
.innerText()
|
||||||
|
|
||||||
|
expect(localeLabel).not.toEqual('English')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('localized text', () => {
|
describe('localized text', () => {
|
||||||
test('create english post, switch to spanish', async () => {
|
test('create english post, switch to spanish', async () => {
|
||||||
|
await changeLocale(page, defaultLocale)
|
||||||
|
|
||||||
await page.goto(url.create)
|
await page.goto(url.create)
|
||||||
|
|
||||||
await fillValues({ description, title })
|
await fillValues({ description, title })
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"paths": {
|
"paths": {
|
||||||
"@payload-config": ["./test/admin/config.ts"],
|
"@payload-config": ["./test/localization/config.ts"],
|
||||||
"@payloadcms/live-preview": ["./packages/live-preview/src"],
|
"@payloadcms/live-preview": ["./packages/live-preview/src"],
|
||||||
"@payloadcms/live-preview-react": ["./packages/live-preview-react/src/index.ts"],
|
"@payloadcms/live-preview-react": ["./packages/live-preview-react/src/index.ts"],
|
||||||
"@payloadcms/live-preview-vue": ["./packages/live-preview-vue/src/index.ts"],
|
"@payloadcms/live-preview-vue": ["./packages/live-preview-vue/src/index.ts"],
|
||||||
|
|||||||
Reference in New Issue
Block a user