SEO 优化
站点元信息、Open Graph、JSON-LD 结构化数据与 sitemap 配置
概览
@01mvp/seo 提供一组 Next.js SEO 工具,统一管理页面标题、描述、Open Graph、Twitter Card 和 JSON-LD 结构化数据。
- 生成一致的
Metadata - 配置站点级名称、域名、作者和默认语言
- 输出 Open Graph 和 Twitter Card
- 安全渲染 JSON-LD
环境变量
| 变量名 | 说明 | 示例 |
|---|---|---|
NEXT_PUBLIC_SITE_URL | 站点完整 URL(含协议) | https://yourdomain.com |
NEXT_PUBLIC_SITE_NAME | 站点名称 | 01MVP |
NEXT_PUBLIC_SITE_DESCRIPTION | 站点默认描述 | A starter kit for indie hackers |
站点元信息配置
创建 Metadata 工厂
import { createMetadataFactory } from "@01mvp/seo";
const createMetadata = createMetadataFactory({
name: process.env.NEXT_PUBLIC_SITE_NAME || "01MVP",
url: process.env.NEXT_PUBLIC_SITE_URL || "https://01mvp.com",
});为页面生成 Metadata
在 Next.js App Router 的页面中导出 metadata:
// app/dashboard/page.tsx
import { createMetadata } from "@/lib/seo";
export const metadata = createMetadata({
title: "Dashboard",
description: "View your workspace and recent activity.",
});createMetadata 会自动拼接站点名称(如 Dashboard - 01MVP),并生成 Open Graph 和 Twitter Card 的默认值。
动态 Metadata
对于需要根据内容动态生成标题的页面,使用 generateMetadata:
export async function generateMetadata({ params }) {
const post = await getPost(params.id);
return createMetadata({
title: post.title,
description: post.summary,
image: post.coverImage,
});
}Open Graph 和 Twitter Card
createMetadata 会自动生成 Open Graph 和 Twitter Card 的元标签。你也可以手动覆盖:
export const metadata = createMetadata({
title: "产品定价",
description: "选择适合你的计划",
openGraph: {
type: "website",
images: ["/images/pricing-og.png"],
},
twitter: {
card: "summary_large_image",
},
});JSON-LD 结构化数据
JSON-LD 帮助搜索引擎理解页面内容。@01mvp/seo 提供了安全渲染组件:
import { JsonLd } from "@01mvp/seo";
export default function HomePage() {
return (
<>
<JsonLd
data={{
"@context": "https://schema.org",
"@type": "WebSite",
name: "01MVP",
url: "https://01mvp.com",
}}
/>
{/* 页面内容 */}
</>
);
}常用 JSON-LD 类型
// 组织信息
<JsonLd
data={{
"@context": "https://schema.org",
"@type": "Organization",
name: "01MVP",
url: "https://01mvp.com",
logo: "https://01mvp.com/images/logo.png",
sameAs: [
"https://twitter.com/01mvp",
"https://github.com/01mvp",
],
}}
/>
// 文章
<JsonLd
data={{
"@context": "https://schema.org",
"@type": "Article",
headline: "如何快速启动一个 SaaS 项目",
author: { "@type": "Person", name: "Your Name" },
datePublished: "2025-01-15",
image: "https://01mvp.com/images/post-cover.png",
}}
/>
// 产品
<JsonLd
data={{
"@context": "https://schema.org",
"@type": "Product",
name: "01MVP Pro",
description: "适用于独立开发者的全栈模板",
offers: {
"@type": "Offer",
price: "99",
priceCurrency: "USD",
},
}}
/>Sitemap 集成
Next.js App Router 原生支持 sitemap。在 app/sitemap.ts 中导出:
// app/sitemap.ts
import type { MetadataRoute } from "next";
export default function sitemap(): MetadataRoute.Sitemap {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || "https://yourdomain.com";
return [
{
url: baseUrl,
lastModified: new Date(),
changeFrequency: "daily",
priority: 1,
},
{
url: `${baseUrl}/pricing`,
lastModified: new Date(),
changeFrequency: "monthly",
priority: 0.8,
},
// 动态页面可以从数据库或 CMS 读取
...posts.map((post) => ({
url: `${baseUrl}/blog/${post.slug}`,
lastModified: post.updatedAt,
changeFrequency: "weekly" as const,
priority: 0.6,
})),
];
}Next.js 会自动在 /sitemap.xml 路径下输出 sitemap 文件。
robots.txt
同样在 App Router 中创建 app/robots.ts:
// app/robots.ts
import type { MetadataRoute } from "next";
export default function robots(): MetadataRoute.Robots {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || "https://yourdomain.com";
return {
rules: [
{
userAgent: "*",
allow: "/",
disallow: ["/api/", "/admin/"],
},
],
sitemap: `${baseUrl}/sitemap.xml`,
};
}注意事项
这个包是可选能力。如果项目只需要基本的 SEO,Next.js 自带的 metadata 导出已经够用。当多个页面或多个 app 需要共享 SEO 默认值时,再接入 @01mvp/seo。