Next.js 16 App Router patterns for this repo (await params/searchParams, next-intl locale handling, Supabase DB-first via services).
apps/web/src/app/**.generateMetadata, caching (revalidate), hoac route handlers.await props.params va await props.searchParams.setRequestLocale(locale) cho page theo locale.next-intl (getTranslations/useTranslations).apps/web/src/services/*-service.ts (khong dung Contentlayer cho blog/docs/projects).export default async function BlogPostPage({
params,
}: {
params: Promise<{ locale: string; slug: string }>
}) {
const { locale, slug } = await params
setRequestLocale(locale)
// ...
}
export default async function BlogPage({
params,
searchParams,
}: {
params: Promise<{ locale: string }>
searchParams: Promise<{ page?: string; tag?: string }>
}) {
// ✅ Toi uu: Await cung luc
const [{ locale }, { page = '1', tag }] = await Promise.all([
params,
searchParams,
])
setRequestLocale(locale)
const posts = await getBlogPosts(locale, 'published', {
page: parseInt(page),
tag,
})
return <BlogList posts={posts} />
}
import { Suspense } from 'react'
export default function BlogPage({ searchParams }: Props) {
return (
<div className="container">
<Header />
<Suspense fallback={<BlogPostsSkeleton />}>
<BlogPosts searchParams={searchParams} />
</Suspense>
<Footer />
</div>
)
}
function BlogPostsSkeleton() {
return (
<div className="space-y-4">
<div className="h-6 w-1/4 animate-pulse bg-gray-200" />
<div className="h-4 w-1/2 animate-pulse bg-gray-200" />
<div className="h-32 w-full animate-pulse bg-gray-200" />
</div>
)
}
Tu dong memoization, khong can useMemo/useCallback thu cong:
// next.config.ts
const nextConfig = {
experimental: {
reactCompiler: true,
},
}
getBlogPosts, getBlogPost tu @/services/blog-service.getPublicDocBySlug tu @/services/docs-service + render runtime bang @/components/docs/mdx-remote.params truc tiep trong signature (vi params la Promise o Next.js 16).apps/web/src/lib/core/** va apps/web/src/components/ui/**.