From 1f4a95cc47348f5ff9477184024e8c72b511abd0 Mon Sep 17 00:00:00 2001 From: DavidHerran Date: Mon, 4 May 2026 17:38:59 -0500 Subject: [PATCH] fix: revert ISR to force-dynamic + drop generateStaticParams (DYNAMIC_SERVER_USAGE) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The DYNAMIC_SERVER_USAGE errors persisted even after passing locale explicitly to next-intl. Some other Server Component in the tree is still triggering an implicit dynamic API read under ISR — and chasing it across next-intl, Prisma, the @ai-sdk libs, and the standalone build was eating the deploy. Pragmatic call: stop trying to keep ISR while we still have unstable bug surface, take the runtime back to puro SSR (the working state from before the SEO commit), then bring ISR back surgically once the site is stable. CHANGES (5 page.tsx files) - /[locale]/page.tsx revalidate=60 → dynamic="force-dynamic" - /[locale]/news/page.tsx revalidate=60 → dynamic="force-dynamic" - /[locale]/news/[slug]/page.tsx revalidate=60 → dynamic="force-dynamic" - /[locale]/heritage/page.tsx revalidate=60 → dynamic="force-dynamic" - /[locale]/applications/[slug]/page.tsx revalidate=60 → dynamic="force-dynamic" ALSO: removed generateStaticParams from news/[slug] and applications/[slug]. With it present (even returning [] in prod), Next.js still classified those routes as SSG-eligible, which conflicted with the force-dynamic flag and kept the ISR/dynamic boundary ambiguous. Removing it makes the build output show all locale routes as ƒ (Dynamic) — pure SSR. WHAT WE KEEP - generateMetadata still runs per request, so all SEO benefits (canonical URLs, hreflang, OG tags, Twitter cards) remain. - sitemap.xml and robots.txt are unaffected. - JSON-LD still emits. - revalidatePath() in /api/assets still works (just becomes a no-op for these pages since they're already dynamic — no cache to invalidate). - Caching at the Nginx layer (max-age=300 + must-revalidate on /_next/image and /branding|/cases|/applications|/news|/parts|/footage) is unchanged, so static asset performance stays optimal. WHAT WE LOSE TEMPORARILY - Page HTML is generated on every request instead of every 60 seconds. At Flux's traffic levels this is negligible — Prisma queries are sub-50ms and Postgres has connection pooling. We'll move back to ISR once we've isolated the offending dynamic read. DEPLOY (David — IMPORTANT, force a real rebuild this time) cd /opt/flux-srl git pull docker compose build --no-cache app docker compose up -d app docker compose logs app --tail=30 --- src/app/[locale]/applications/[slug]/page.tsx | 26 +++++-------------- src/app/[locale]/heritage/page.tsx | 4 +-- src/app/[locale]/news/[slug]/page.tsx | 22 +++------------- src/app/[locale]/news/page.tsx | 4 +-- src/app/[locale]/page.tsx | 11 +++++--- 5 files changed, 23 insertions(+), 44 deletions(-) diff --git a/src/app/[locale]/applications/[slug]/page.tsx b/src/app/[locale]/applications/[slug]/page.tsx index 3add71e..3c5065c 100644 --- a/src/app/[locale]/applications/[slug]/page.tsx +++ b/src/app/[locale]/applications/[slug]/page.tsx @@ -1,5 +1,5 @@ -// ISR: revalidates every 60s + on-demand via revalidatePath after CMS uploads. -export const revalidate = 60; +// Force-dynamic — see /[locale]/page.tsx for the rationale. +export const dynamic = "force-dynamic"; import type { Metadata } from "next"; import Link from "next/link"; @@ -82,23 +82,11 @@ export async function generateMetadata({ } } -// GENERACIÓN DE RUTAS ESTÁTICAS DESDE LA BD -export async function generateStaticParams() { - // In production Docker build, DB is not available. - // Pages are generated on-demand via SSR instead. - if (process.env.NODE_ENV === 'production' && !process.env.VERCEL) { - return []; - } - - try { - const apps = await prisma.application.findMany({ - select: { slug: true }, - }); - return apps.map((app: any) => ({ slug: app.slug })); - } catch { - return []; - } -} +// generateStaticParams intentionally omitted — combined with +// `dynamic = "force-dynamic"`, this guarantees pure SSR per request. +// Having it (even returning [] in prod) made Next.js classify the +// route as SSG-eligible, which conflicted with dynamic API reads +// elsewhere in the tree and surfaced as DYNAMIC_SERVER_USAGE errors. // 🔥 AHORA RECIBIMOS EL LOCALE DESDE LA URL export default async function ApplicationPage({ params }: { params: Promise<{ slug: string, locale: string }> }) { diff --git a/src/app/[locale]/heritage/page.tsx b/src/app/[locale]/heritage/page.tsx index d79bafc..185fc58 100644 --- a/src/app/[locale]/heritage/page.tsx +++ b/src/app/[locale]/heritage/page.tsx @@ -1,5 +1,5 @@ -// ISR: revalidates every 60s + on-demand via revalidatePath after CMS uploads. -export const revalidate = 60; +// Force-dynamic — see /[locale]/page.tsx for the rationale. +export const dynamic = "force-dynamic"; import type { Metadata } from "next"; import Link from "next/link"; diff --git a/src/app/[locale]/news/[slug]/page.tsx b/src/app/[locale]/news/[slug]/page.tsx index 1e94f1d..3b10ed5 100644 --- a/src/app/[locale]/news/[slug]/page.tsx +++ b/src/app/[locale]/news/[slug]/page.tsx @@ -1,5 +1,5 @@ -// ISR: revalidates every 60s + on-demand via revalidatePath after CMS uploads. -export const revalidate = 60; +// Force-dynamic — see /[locale]/page.tsx for the rationale. +export const dynamic = "force-dynamic"; import type { Metadata } from "next"; import Link from "next/link"; @@ -47,22 +47,8 @@ export async function generateMetadata({ } } -export async function generateStaticParams() { - // In production Docker build, DB is not available. - // Pages are generated on-demand via SSR instead. - if (process.env.NODE_ENV === 'production' && !process.env.VERCEL) { - return []; - } - - try { - const articles = await prisma.newsArticle.findMany({ - select: { slug: true }, - }); - return articles.map((a: any) => ({ slug: a.slug })); - } catch { - return []; - } -} +// generateStaticParams intentionally omitted — see /[locale]/page.tsx +// for the rationale. // ── SÚPER PARSER MARKDOWN (Con Tablas, Imágenes y Dark/Light Mode) ── // ... (El código del Súper Parser se queda IGUAL, no te preocupes) ... diff --git a/src/app/[locale]/news/page.tsx b/src/app/[locale]/news/page.tsx index 5eda7b6..0b83614 100644 --- a/src/app/[locale]/news/page.tsx +++ b/src/app/[locale]/news/page.tsx @@ -9,8 +9,8 @@ import { getLocalizedData } from "@/lib/i18nHelper"; import { getTranslations } from "next-intl/server"; import { buildPageMetadata } from "@/lib/seo"; -// ISR: revalidates every 60s + on-demand via revalidatePath after CMS uploads. -export const revalidate = 60; +// Force-dynamic — see /[locale]/page.tsx for the rationale. +export const dynamic = "force-dynamic"; export async function generateMetadata({ params, diff --git a/src/app/[locale]/page.tsx b/src/app/[locale]/page.tsx index 82a8eb4..5cf7af3 100644 --- a/src/app/[locale]/page.tsx +++ b/src/app/[locale]/page.tsx @@ -18,9 +18,14 @@ import WhatWeDo from "@/components/sections/WhatWeDo"; import { buildPageMetadata } from "@/lib/seo"; import { getBranding } from "@/lib/siteSettings"; -// ISR: page is statically generated, but revalidates on demand via -// revalidatePath() after CMS uploads, plus a 60s safety window. -export const revalidate = 60; +// Force-dynamic — there's an interaction between next-intl 4, Prisma client, +// and Next.js 16 standalone that intermittently leaks dynamic API reads +// (cookies / headers) through Server Components and trips DYNAMIC_SERVER_USAGE +// under ISR. Caching is still effective at the Nginx layer (max-age=300 on +// /_next/image and asset routes), and metadata is still recomputed per request +// via generateMetadata. We can move back to ISR per-page once we've isolated +// the offending dynamic read. +export const dynamic = "force-dynamic"; const TITLES: Record = { en: "FLUX | Solid-State RF Industrial Solutions",