fix createContentHelpers.ts
This commit is contained in:
@@ -194,77 +194,91 @@ export function createContentHelpers({
|
||||
const generateStaticParams = async (): Promise<
|
||||
Array<{ locale: string; slug: string[] } | { slug: string[] }>
|
||||
> => {
|
||||
const payload = await getCachedPayload()
|
||||
const locales = i18n ? i18n.locales.map((l) => l.code) : [undefined]
|
||||
const singleLocale = !i18n || i18n.locales.length === 1
|
||||
try {
|
||||
const payload = await getCachedPayload()
|
||||
const locales = i18n ? i18n.locales.map((l) => l.code) : [undefined]
|
||||
const singleLocale = !i18n || i18n.locales.length === 1
|
||||
|
||||
// Home slug per locale, to exclude the homepage (it's the root, slug []).
|
||||
const settings = (await payload
|
||||
.findGlobal({ slug: settingsSlug as never, depth: 1, locale: 'all' as never })
|
||||
.catch(() => null)) as { homepage?: { id?: number | string; slug?: unknown } } | null
|
||||
const homeId = settings?.homepage?.id
|
||||
// Home slug per locale, to exclude the homepage (it's the root, slug []).
|
||||
const settings = (await payload
|
||||
.findGlobal({ slug: settingsSlug as never, depth: 1, locale: 'all' as never })
|
||||
.catch(() => null)) as { homepage?: { id?: number | string; slug?: unknown } } | null
|
||||
const homeId = settings?.homepage?.id
|
||||
|
||||
const EXCLUDED = new Set(['404', '500', 'error', 'not-found'])
|
||||
const params: Array<{ locale: string; slug: string[] } | { slug: string[] }> = []
|
||||
const EXCLUDED = new Set(['404', '500', 'error', 'not-found'])
|
||||
const params: Array<{ locale: string; slug: string[] } | { slug: string[] }> = []
|
||||
|
||||
for (const locale of locales) {
|
||||
// NO where:{_status} filter — collections without drafts enabled don't
|
||||
// register the _status field, and querying it throws
|
||||
// "path cannot be queried: _status". We filter drafts in memory below,
|
||||
// which is safe for every collection (with or without drafts).
|
||||
const result = await payload.find({
|
||||
collection: pagesSlug as never,
|
||||
depth: 0,
|
||||
limit: 1000,
|
||||
locale: (locale ?? 'all') as never,
|
||||
})
|
||||
for (const locale of locales) {
|
||||
// NO where:{_status} filter — collections without drafts enabled don't
|
||||
// register the _status field, and querying it throws
|
||||
// "path cannot be queried: _status". We filter drafts in memory below,
|
||||
// which is safe for every collection (with or without drafts).
|
||||
const result = await payload.find({
|
||||
collection: pagesSlug as never,
|
||||
depth: 0,
|
||||
limit: 1000,
|
||||
locale: (locale ?? 'all') as never,
|
||||
})
|
||||
|
||||
for (const raw of result.docs as Array<{
|
||||
_status?: string
|
||||
id: number | string
|
||||
meta?: { noindex?: boolean } | null
|
||||
slug?: unknown
|
||||
}>) {
|
||||
// Draft filter in memory (safe whether or not the collection has drafts).
|
||||
if (raw._status && raw._status !== 'published') {continue}
|
||||
for (const raw of result.docs as Array<{
|
||||
_status?: string
|
||||
id: number | string
|
||||
meta?: { noindex?: boolean } | null
|
||||
slug?: unknown
|
||||
}>) {
|
||||
// Draft filter in memory (safe whether or not the collection has drafts).
|
||||
if (raw._status && raw._status !== 'published') {continue}
|
||||
|
||||
// NOTE: unlike the sitemap, we do NOT skip meta.noindex here. A noindex
|
||||
// page (privacy, cookies, terms) still needs to render — users reach it
|
||||
// from the footer and crawlers read its <meta robots=noindex>. Pre-render
|
||||
// it as SSG so it's fast and its <head> is complete; noindex controls
|
||||
// INDEXING, not whether the page exists. Skipping it would force dynamic
|
||||
// rendering (the very streaming problem we're avoiding).
|
||||
// NOTE: unlike the sitemap, we do NOT skip meta.noindex here. A noindex
|
||||
// page (privacy, cookies, terms) still needs to render — users reach it
|
||||
// from the footer and crawlers read its <meta robots=noindex>. Pre-render
|
||||
// it as SSG so it's fast and its <head> is complete; noindex controls
|
||||
// INDEXING, not whether the page exists. Skipping it would force dynamic
|
||||
// rendering (the very streaming problem we're avoiding).
|
||||
|
||||
if (homeId && raw.id === homeId) {
|
||||
// Homepage → root. Emit an empty-slug param so '/' (or '/pl') builds.
|
||||
const empty = singleLocale ? { slug: [] } : { slug: [], locale: locale as string }
|
||||
if (!params.some((p) => JSON.stringify(p) === JSON.stringify(empty))) {params.push(empty)}
|
||||
continue
|
||||
if (homeId && raw.id === homeId) {
|
||||
// Homepage → root. Emit an empty-slug param so '/' (or '/pl') builds.
|
||||
const empty = singleLocale ? { slug: [] } : { slug: [], locale: locale as string }
|
||||
if (!params.some((p) => JSON.stringify(p) === JSON.stringify(empty))) {params.push(empty)}
|
||||
continue
|
||||
}
|
||||
|
||||
// Slug may be a plain string OR a localized map ({ pl: 'kontakt' }) when
|
||||
// read with locale:'all' or left unflattened. Handle both, or localized
|
||||
// pages get silently dropped.
|
||||
const rawSlug = raw.slug
|
||||
const slug =
|
||||
typeof rawSlug === 'string'
|
||||
? rawSlug
|
||||
: rawSlug && typeof rawSlug === 'object'
|
||||
? (((rawSlug as Record<string, unknown>)[locale ?? ''] as string | undefined) ??
|
||||
(Object.values(rawSlug as Record<string, unknown>)[0] as string | undefined))
|
||||
: undefined
|
||||
|
||||
if (!slug || EXCLUDED.has(slug)) {continue}
|
||||
|
||||
// Multi-level slugs ('atrakcje/telefon') → array segments.
|
||||
const segments = String(slug).split('/').filter(Boolean)
|
||||
params.push(
|
||||
singleLocale ? { slug: segments } : { slug: segments, locale: locale as string },
|
||||
)
|
||||
}
|
||||
|
||||
// Slug may be a plain string OR a localized map ({ pl: 'kontakt' }) when
|
||||
// read with locale:'all' or left unflattened. Handle both, or localized
|
||||
// pages get silently dropped.
|
||||
const rawSlug = raw.slug
|
||||
const slug =
|
||||
typeof rawSlug === 'string'
|
||||
? rawSlug
|
||||
: rawSlug && typeof rawSlug === 'object'
|
||||
? (((rawSlug as Record<string, unknown>)[locale ?? ''] as string | undefined) ??
|
||||
(Object.values(rawSlug as Record<string, unknown>)[0] as string | undefined))
|
||||
: undefined
|
||||
|
||||
if (!slug || EXCLUDED.has(slug)) {continue}
|
||||
|
||||
// Multi-level slugs ('atrakcje/telefon') → array segments.
|
||||
const segments = String(slug).split('/').filter(Boolean)
|
||||
params.push(
|
||||
singleLocale ? { slug: segments } : { slug: segments, locale: locale as string },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return params
|
||||
return params
|
||||
} catch (err) {
|
||||
// DB unreachable — typically a container build (Docker/Coolify/CI) with no
|
||||
// database network. Return [] so the build doesn't crash: Next falls back
|
||||
// to on-demand rendering for the routes, which fill in once the DB is
|
||||
// reachable at runtime. Without this every project would need its own
|
||||
// try/catch here. (Same graceful-degradation as the sitemap handler.)
|
||||
console.warn(
|
||||
'[ipal] generateStaticParams: database not reachable during build ' +
|
||||
'(Docker/CI) — returning empty params; routes render on-demand at runtime:',
|
||||
err,
|
||||
)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user