跳转到主要内容
杨月昌的软件博客
返回

使用 Sanity CMS + Next.js 构建高性能内容驱动型应用

### 1. 为什么在 Jamstack 架构中选择 Sanity?

在现代 Web 开发中,Jamstack (JavaScript, API, Markup) 已成为构建快速、安全网站的主流方案。而 Sanity CMS 作为一款“无头(Headless)”内容平台,与传统的 CMS 有本质不同:


### 2. 核心:无头 CMS 的五大优势

  1. 安全性:后端数据库不直接暴露在公网,通过 API 令牌访问,极大减小了被攻击的可能性。
  2. 多渠道分发:一次编写,随处运行。
  3. 灵活建模:不再受限于 WordPress 的“文章/页面”模式,你可以自由定义 Project, Author, Service 等任何模型。
  4. 卓越的开发者体验 (DX):通过 CLI 工具快速初始化,API 驱动的开发流程符合现代工程习惯。
  5. 增量静态再生 (ISR):配合 Next.js,可以在内容更新后自动触发部分页面重新构建,无需全量更新。

### 3. 实战指南:集成 Sanity 到 Next.js

#### 第一步:初始化 Next.js 前端

npx create-next-app@latest client
cd client
npm dev

#### 第二步:搭建 Sanity Studio

在项目根目录外或子目录中,初始化 Sanity:

npm install -g @sanity/cli
sanity init

选择默认设置后,进入 cms 目录启动管理后台:

cd cms
sanity start -p 3333

#### 第三步:定义内容模型 (Schema)

schemas/homepage.js 中,我们不仅定义字段,还添加一些辅助信息:

export default {
  name: 'homepage',
  title: '首页内容',
  type: 'document',
  fields: [
    { 
      name: 'title', 
      title: '主标题', 
      type: 'string',
      validation: Rule => Rule.required() // 添加简单校验
    },
    { name: 'subtitle', title: '副标题', type: 'string' },
    { 
      name: 'image', 
      title: '封面图片', 
      type: 'image',
      options: { hotspot: true } // 允许在后台在线裁剪图片
    },
    { name: 'cta', title: '行动呼吁 (URL)', type: 'slug' },
  ],
};

#### 第四步:配置 Next.js 连接器

安装必要依赖:

npm install @sanity/client @sanity/image-url

lib/sanity.js 中封装客户端(注意:现代版本建议使用 createClient):

import { createClient } from '@sanity/client';
import imageUrlBuilder from '@sanity/image-url';

export const client = createClient({
  projectId: 'your_project_id',
  dataset: 'production',
  apiVersion: '2022-03-07', // 指定 API 版本
  useCdn: true, // 使用 CDN 加速获取数据
});

// 处理图片 URL 的辅助函数
const builder = imageUrlBuilder(client);
export const urlFor = (source) => builder.image(source);

#### 第五步:使用 GROQ 查询并渲染

pages/index.js 中利用 getStaticProps 实现高性能加载:

import { client, urlFor } from '../lib/sanity';

const homepageQuery = `*[_type == "homepage"][0]{
  title,
  subtitle,
  "ctaUrl": cta.current,
  image
}`;

export async function getStaticProps() {
  const data = await client.fetch(homepageQuery);
  return {
    props: { data },
    revalidate: 10, // 每 10 秒尝试重新验证内容
  };
}

export default function Home({ data }) {
  return (
    <main style={{ maxWidth: '800px', margin: '0 auto' }}>
      <h1>{data.title}</h1>
      {data.image && (
        <img 
          src={urlFor(data.image).width(800).url()} 
          alt={data.title} 
        />
      )}
      <p>{data.subtitle}</p>
      <a href={data.ctaUrl} className="btn">立即开始</a>
    </main>
  );
}

### 4. 总结与进阶建议

通过将 SanityNext.js 结合,你拥有了一个兼具“静态网站性能”和“动态内容管理灵活性”的架构。



上一篇
WPF 中的 DataContext 与 View-ViewModel 绑定方式详解
下一篇
简单升级 Hexo 的方法:一键三连助你轻松搞定