name: seo-handler description: 管理SEO、站点地图和元数据,以实现最佳搜索引擎可见性 tools: 读取、写入、编辑 model: 继承
SEO处理技能
此技能确保您的Next.js应用程序针对搜索引擎进行优化。它涵盖站点地图、元数据(OpenGraph)、服务器端渲染(SSR/ISR)、结构化数据(JSON-LD)和robots.txt配置。
核心原则
- 站点地图可见性:每个公共页面必须位于
src/app/sitemap.ts中。 - 元数据继承:在
layout.tsx中设置默认值;在page.tsx中覆盖。 - 结构化数据:在每个内容页面上使用
next-seo组件(JSON-LD)。 - 服务器端数据:在服务器上获取内容密集型数据(ISR)以利于SEO。
- 机器人控制:使用
src/app/robots.ts来引导爬虫。
1. 站点地图管理
文件:src/app/sitemap.ts
添加新的公共路由(例如,/features)时,将其添加到staticPages数组中。
const staticPages = [
"", // 首页
"/features", // 新页面
// ...
];
拆分站点地图(大型网站)
如果您拥有超过5万个URL(例如,用户个人资料、产品),请使用generateSitemaps。
文件:src/app/products/sitemap.ts
import { BASE_URL } from '@/lib/constants';
export async function generateSitemaps() {
// 获取总数并按批次大小(例如,50,000)划分
return [{ id: 0 }, { id: 1 }];
}
export default async function sitemap({ id }: { id: { id: number } }) {
const start = id.id * 50000;
const products = await getProducts(start, 50000);
return products.map(product => ({
url: `${BASE_URL}/products/${product.slug}`,
lastModified: product.updatedAt,
}));
}
2. 元数据与OpenGraph
基础布局:src/app/layout.tsx(或分组布局)定义模板。
export const metadata: Metadata = {
title: {
template: "%s | 我的应用",
default: "我的应用 - 最佳SaaS",
},
description: "...",
openGraph: { ... }, // 默认OG
};
页面级别:src/app/blog/[slug]/page.tsx
export async function generateMetadata({ params }): Promise<Metadata> {
const post = await getPost(params.slug);
return {
title: post.title,
description: post.summary,
openGraph: {
images: [post.coverImage], // 覆盖默认值
},
};
}
3. 结构化数据(JSON-LD)
主要:Next-SEO组件
使用next-seo组件注入JSON-LD结构化数据。这有助于搜索引擎理解您的内容(文章、产品、常见问题解答等)。
页面组件:src/app/blog/[slug]/page.tsx
import { ArticleJsonLd } from "next-seo";
export default function BlogPost({ post }) {
return (
<>
<ArticleJsonLd
useAppDir
url={`https://myapp.com/blog/${post.slug}`}
title={post.title}
images={[post.image]}
datePublished={post.date}
authorName="我的应用"
description={post.description}
/>
<article>...</article>
</>
);
}
替代方案:原始JSON-LD(脚本标签)
如果特定架构不受next-seo支持,请使用原始脚本标签。如果数据获取是异步的,请用Suspense包装。
import { Suspense } from "react";
export default function Page() {
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'CustomType',
name: '自定义名称',
description: '描述',
};
return (
<section>
<Suspense fallback={null}>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
</Suspense>
{/* 页面内容 */}
</section>
);
}
4. 增量静态再生(ISR)
对于依赖数据库内容的内容页面(博客、文档、营销),使用ISR在边缘缓存它们。
页面组件:
// src/app/blog/[slug]/page.tsx
// 1. 启用ISR
export const revalidate = 3600; // 每小时重新验证(以秒为单位)
// 或者使用动态参数和generateStaticParams以实现完整的静态导出行为
export const dynamicParams = true;
export async function generateStaticParams() {
const posts = await db.query.posts.findMany();
return posts.map((post) => ({ slug: post.slug }));
}
export default async function BlogPost({ params }) {
// 2. 在服务器上获取(数据根据revalidate配置缓存)
const post = await getPost(params.slug);
return <article>{/* ... */}</article>;
}
5. Robots.txt配置
文件:src/app/robots.txt
确保禁止私有路由(/api/、/app/、/admin/)以节省爬虫预算。
export default function robots(): MetadataRoute.Robots {
return {
rules: {
userAgent: "*",
allow: "/",
disallow: ["/api/", "/app/", "/super-admin/"],
},
sitemap: `${process.env.NEXT_PUBLIC_APP_URL}/sitemap.xml`,
};
}