-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpage.tsx
More file actions
70 lines (62 loc) · 2.33 KB
/
Copy pathpage.tsx
File metadata and controls
70 lines (62 loc) · 2.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import type { Metadata } from 'next';
import { notFound } from 'next/navigation';
import Link from 'next/link';
import { getPost } from '@/lib/cms';
import { buildMetadata } from '@/lib/seo/metadata';
// Next.js 15+ made dynamic route `params` async. In Next.js 16 the synchronous
// shape is gone entirely: `params` is a Promise and MUST be awaited. Using the
// old `{ params }: { params: { slug: string } }` shape is the canonical bug
// this starter refuses to reintroduce.
interface BlogPageProps {
params: Promise<{ slug: string }>;
}
// Render at request time, not build time. The canonical / OG url / metadataBase
// are derived from SITE_ORIGIN (see lib/seo/env.ts), which is resolved
// per-process at runtime. Rendering at request time is what lets the SAME build
// emit preview-correct canonicals on a preview deploy and production canonicals
// in production. Static prerendering would freeze the build-time origin into the
// HTML and leak it across environments — the exact regression this starter
// prevents (preview must never emit production canonicals).
export const dynamic = 'force-dynamic';
export async function generateMetadata({ params }: BlogPageProps): Promise<Metadata> {
const { slug } = await params;
const post = await getPost(slug);
// No record -> the page will call notFound(); return minimal metadata.
if (!post) {
return { title: 'Not found', robots: { index: false, follow: false } };
}
return buildMetadata({
title: post.title,
description: post.excerpt,
seo: post.seo,
path: `/blog/${post.slug}`,
ogType: 'article',
});
}
export default async function BlogPostPage({ params }: BlogPageProps) {
const { slug } = await params;
const post = await getPost(slug);
// Missing OR unpublished (draft/archived) -> a REAL 404, never a soft-404
// (a 200 with a "not found" body). getPost already filters to published.
if (!post) {
notFound();
}
return (
<article>
<p>
<Link href="/">← Home</Link>
</p>
<h1>{post.title}</h1>
<p>
<em>{post.excerpt}</em>
</p>
<p>{post.body}</p>
<p style={{ color: '#666', fontSize: '0.9rem' }}>
Last updated:{' '}
<time dateTime={post.contentUpdatedAt}>
{new Date(post.contentUpdatedAt).toISOString().slice(0, 10)}
</time>
</p>
</article>
);
}