From f1878d57ee4a52944d3569d8543f413cded1b6ff Mon Sep 17 00:00:00 2001 From: f-amine Date: Sun, 28 Jun 2026 00:52:36 +0100 Subject: [PATCH 1/2] fix(marketing): enable next-intl static rendering for docs/blog/changelog Docs, blog, and changelog pages threw DYNAMIC_SERVER_USAGE in production: the [locale] layout called getMessages() without setRequestLocale and had no locale generateStaticParams, so next-intl fell back to headers() and every prerendered route became dynamic at render time. - [locale]/layout: add generateStaticParams over LOCALES + setRequestLocale - docs/blog/changelog pages: thread locale param + setRequestLocale - blog/changelog generateStaticParams: map fumadocs string[] slug to the single [slug] segment (surfaced once prerender actually ran) Co-Authored-By: Claude Opus 4.8 (1M context) --- .../marketing/src/app/[locale]/blog/[slug]/page.tsx | 11 ++++++++--- .../src/app/[locale]/changelog/[slug]/page.tsx | 11 ++++++++--- .../src/app/[locale]/docs/[[...slug]]/page.tsx | 6 ++++-- apps/marketing/src/app/[locale]/layout.tsx | 13 ++++++++++++- 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/apps/marketing/src/app/[locale]/blog/[slug]/page.tsx b/apps/marketing/src/app/[locale]/blog/[slug]/page.tsx index 2c76a73..0956507 100644 --- a/apps/marketing/src/app/[locale]/blog/[slug]/page.tsx +++ b/apps/marketing/src/app/[locale]/blog/[slug]/page.tsx @@ -3,6 +3,7 @@ import type { Metadata } from "next"; import Image from "next/image"; import Link from "next/link"; import { notFound } from "next/navigation"; +import { setRequestLocale } from "next-intl/server"; import { MarketingFooter } from "@/components/marketing/footer"; import { MarketingHeader } from "@/components/marketing/header"; import { BlogPostingJsonLd } from "@/components/seo/json-ld"; @@ -10,7 +11,7 @@ import { ogMetadata, siteBase } from "@/lib/og"; import { blogSource } from "@/lib/source"; type Props = { - params: Promise<{ slug: string }>; + params: Promise<{ locale: string; slug: string }>; }; type PostData = { @@ -24,7 +25,10 @@ type PostData = { }; export async function generateStaticParams() { - return blogSource.generateParams(); + // Route is a single [slug] segment; fumadocs yields slug as a string[]. + return blogSource + .generateParams() + .map(({ slug }) => ({ slug: slug.join("/") })); } export async function generateMetadata({ params }: Props): Promise { @@ -58,7 +62,8 @@ function formatDate(input?: string): string { } export default async function BlogPost({ params }: Props) { - const { slug } = await params; + const { locale, slug } = await params; + setRequestLocale(locale); const page = blogSource.getPage([slug]); if (!page) notFound(); const MDX = page.data.body; diff --git a/apps/marketing/src/app/[locale]/changelog/[slug]/page.tsx b/apps/marketing/src/app/[locale]/changelog/[slug]/page.tsx index 04c04de..56871b9 100644 --- a/apps/marketing/src/app/[locale]/changelog/[slug]/page.tsx +++ b/apps/marketing/src/app/[locale]/changelog/[slug]/page.tsx @@ -1,15 +1,19 @@ import type { Metadata } from "next"; import { notFound } from "next/navigation"; +import { setRequestLocale } from "next-intl/server"; import { TechArticleJsonLd } from "@/components/seo/json-ld"; import { ogMetadata, siteBase } from "@/lib/og"; import { changelogSource } from "@/lib/source"; type Props = { - params: Promise<{ slug: string }>; + params: Promise<{ locale: string; slug: string }>; }; export async function generateStaticParams() { - return changelogSource.generateParams(); + // Route is a single [slug] segment; fumadocs yields slug as a string[]. + return changelogSource + .generateParams() + .map(({ slug }) => ({ slug: slug.join("/") })); } export async function generateMetadata({ params }: Props): Promise { @@ -31,7 +35,8 @@ export async function generateMetadata({ params }: Props): Promise { } export default async function ChangelogEntryPage({ params }: Props) { - const { slug } = await params; + const { locale, slug } = await params; + setRequestLocale(locale); const page = changelogSource.getPage([slug]); if (!page) { notFound(); diff --git a/apps/marketing/src/app/[locale]/docs/[[...slug]]/page.tsx b/apps/marketing/src/app/[locale]/docs/[[...slug]]/page.tsx index 5dd5011..d97f892 100644 --- a/apps/marketing/src/app/[locale]/docs/[[...slug]]/page.tsx +++ b/apps/marketing/src/app/[locale]/docs/[[...slug]]/page.tsx @@ -6,12 +6,13 @@ import { } from "fumadocs-ui/page"; import type { Metadata } from "next"; import { notFound } from "next/navigation"; +import { setRequestLocale } from "next-intl/server"; import { TechArticleJsonLd } from "@/components/seo/json-ld"; import { ogMetadata, siteBase } from "@/lib/og"; import { source } from "@/lib/source"; type Props = { - params: Promise<{ slug?: string[] }>; + params: Promise<{ locale: string; slug?: string[] }>; }; export async function generateStaticParams() { @@ -41,7 +42,8 @@ export async function generateMetadata({ params }: Props): Promise { } export default async function DocsPageRoute({ params }: Props) { - const { slug } = await params; + const { locale, slug } = await params; + setRequestLocale(locale); const page = source.getPage(slug); if (!page) notFound(); const MDX = page.data.body; diff --git a/apps/marketing/src/app/[locale]/layout.tsx b/apps/marketing/src/app/[locale]/layout.tsx index 41ac55e..5b6157a 100644 --- a/apps/marketing/src/app/[locale]/layout.tsx +++ b/apps/marketing/src/app/[locale]/layout.tsx @@ -1,8 +1,9 @@ import { GoogleAnalytics } from "@vibestack/analytics/ga"; +import { LOCALES } from "@vibestack/i18n"; import type { Metadata } from "next"; import { Fraunces, Geist, JetBrains_Mono } from "next/font/google"; import { NextIntlClientProvider } from "next-intl"; -import { getMessages } from "next-intl/server"; +import { getMessages, setRequestLocale } from "next-intl/server"; import { ThemeProvider } from "next-themes"; import type { ReactNode } from "react"; import { Toaster } from "sonner"; @@ -62,8 +63,18 @@ type Props = { params: Promise<{ locale: string }>; }; +// Prerender both locales so docs/blog/changelog static params can fan out +// under each. Without this the [locale] segment is request-time only. +export function generateStaticParams() { + return LOCALES.map((locale) => ({ locale })); +} + export default async function LocaleLayout({ children, params }: Props) { const { locale } = await params; + // Opt into static rendering for next-intl: pins the locale into the request + // store so getMessages()/translations don't fall back to headers() (which + // would make every page dynamic and throw DYNAMIC_SERVER_USAGE on prerender). + setRequestLocale(locale); const messages = await getMessages(); return ( Date: Sun, 28 Jun 2026 01:02:15 +0100 Subject: [PATCH 2/2] fix(marketing): align hero CTAs to equal height, drop stray blur Give the primary CTA a transparent border so its box height matches the outlined GitHub button in the same row; remove leftover backdrop-blur. Co-Authored-By: Claude Opus 4.8 (1M context) --- apps/marketing/src/components/marketing/sections/hero.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/marketing/src/components/marketing/sections/hero.tsx b/apps/marketing/src/components/marketing/sections/hero.tsx index 46b4477..fa7263f 100644 --- a/apps/marketing/src/components/marketing/sections/hero.tsx +++ b/apps/marketing/src/components/marketing/sections/hero.tsx @@ -98,7 +98,7 @@ export function Hero({ stars }: { stars?: number | null }) {