Upgrade to Next.js 16 with Turbopack and Contentlayer2

- Upgraded Next.js to v16, React to v19
- Migrated from contentlayer to contentlayer2
- Migrated to Turbopack by decoupling Contentlayer from webpack
- Updated all page components to handle async params (Next.js 15+ breaking change)
- Changed package.json to type: module and renamed config files to .cjs
- Updated README with current tech stack and article creation instructions
- Fixed tag encoding issue (removed double encoding)
- All security vulnerabilities resolved (npm audit: 0 vulnerabilities)
This commit is contained in:
2025-11-19 22:43:14 +08:00
parent 4c08413936
commit a4db9688b6
11 changed files with 1435 additions and 427 deletions

View File

@@ -20,11 +20,11 @@ export function generateStaticParams() {
}
interface Props {
params: { slug: string };
params: Promise<{ slug: string }>;
}
export function generateMetadata({ params }: Props): Metadata {
const slug = params.slug;
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { slug } = await params;
const post = getPostBySlug(slug);
if (!post) return {};
@@ -34,8 +34,8 @@ export function generateMetadata({ params }: Props): Metadata {
};
}
export default function BlogPostPage({ params }: Props) {
const slug = params.slug;
export default async function BlogPostPage({ params }: Props) {
const { slug } = await params;
const post = getPostBySlug(slug);
if (!post) return notFound();

View File

@@ -17,11 +17,11 @@ export function generateStaticParams() {
}
interface Props {
params: { slug: string };
params: Promise<{ slug: string }>;
}
export function generateMetadata({ params }: Props): Metadata {
const slug = params.slug;
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { slug } = await params;
const page = getPageBySlug(slug);
if (!page) return {};
@@ -31,8 +31,8 @@ export function generateMetadata({ params }: Props): Metadata {
};
}
export default function StaticPage({ params }: Props) {
const slug = params.slug;
export default async function StaticPage({ params }: Props) {
const { slug } = await params;
const page = getPageBySlug(slug);
if (!page) return notFound();

View File

@@ -22,11 +22,11 @@ export function generateStaticParams() {
}
interface Props {
params: { tag: string };
params: Promise<{ tag: string }>;
}
export function generateMetadata({ params }: Props): Metadata {
const slug = params.tag;
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { tag: slug } = await params;
// Find original tag label by slug
const tag = allPosts
.flatMap((post) => post.tags ?? [])
@@ -37,15 +37,15 @@ export function generateMetadata({ params }: Props): Metadata {
};
}
export default function TagPage({ params }: Props) {
const slug = params.tag;
export default async function TagPage({ params }: Props) {
const { tag: slug } = await params;
const posts = allPosts.filter(
(post) => post.tags && post.tags.some((t) => getTagSlug(t) === slug)
);
const tagLabel =
posts[0]?.tags?.find((t) => getTagSlug(t) === slug) ?? params.tag;
posts[0]?.tags?.find((t) => getTagSlug(t) === slug) ?? slug;
return (
<SidebarLayout>