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

相关资源