fix(ecommerce): render product detail dynamically instead of stale SSG+ISR
Product detail pages were generateStaticParams'd at Docker build time, where MEDUSA_* env vars aren't set, so the static snapshot baked in the mock catalog (price: null for all products). With revalidate=60 and no shared ISR cache handler across the 2 frontend replicas, each pod healed its own cache independently on next visit past staleness — so a product could show "Consultar precio" on one pod and the real price on the other, while the fully-dynamic catalog listing always hit Medusa fresh. Verified against the live Medusa API that pricing/region data itself was correct for the reported failing products. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01DXqBoNfYQNwFg65mbx2FWM
This commit is contained in:
@@ -9,17 +9,17 @@ import { getProductBySlug, getProducts } from "@/lib/headless/client";
|
||||
|
||||
interface ProductPageProps { params: Promise<{ slug: string }> }
|
||||
|
||||
// Sin esto, la página queda estática para siempre con los datos del build
|
||||
// (que usa el catálogo mock porque HEADLESS_PROVIDER/MEDUSA_* no existen en
|
||||
// el contexto del Docker build). El listado sí se refresca porque su ruta
|
||||
// es dinámica por searchParams; esta ruta necesita el revalidate explícito
|
||||
// para que el runtime (que sí tiene las env vars de Medusa) la regenere.
|
||||
export const revalidate = 60;
|
||||
|
||||
export async function generateStaticParams() {
|
||||
const products = await getProducts();
|
||||
return products.map((product) => ({ slug: product.slug }));
|
||||
}
|
||||
// generateStaticParams + revalidate quedaban aquí para pre-renderizar en
|
||||
// build time, pero HEADLESS_PROVIDER/MEDUSA_* no existen en el contexto del
|
||||
// Docker build: el snapshot estático quedaba congelado con el catálogo mock
|
||||
// (todos los productos con price: null) hasta que ISR lo revalidara. Con
|
||||
// frontend-deploy corriendo 2 réplicas y sin cacheHandler compartido, cada
|
||||
// pod revalida su propia caché de forma independiente, así que un producto
|
||||
// podía mostrar "Consultar precio" en un pod y el precio real en el otro
|
||||
// según cuál hubiera sido "calentado". force-dynamic elimina esa caché por
|
||||
// pod y deja esta ruta en vivo contra Medusa, igual que el listado
|
||||
// (dinámico por searchParams).
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export async function generateMetadata({ params }: ProductPageProps): Promise<Metadata> {
|
||||
const { slug } = await params;
|
||||
|
||||
Reference in New Issue
Block a user