804 字
4 分钟
使用 Sanity CMS + Next.js 构建高性能内容驱动型应用

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

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

  • 内容即数据(Content as Data):Sanity 不存储 HTML,而是存储结构化的 JSON 格式。这意味着一份内容可以无缝分发到网站、移动端甚至是智能手表。
  • 解耦的 Studio:Sanity Studio 是一个基于 React 的开源编辑界面。你可以根据需求,像开发普通 React 应用一样定制复杂的输入控件。
  • 强大的查询语言 GROQ:比 GraphQL 更简洁、更灵活,专为 JSON 数据查询设计。

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

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

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

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

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

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

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

Terminal window
npm install -g @sanity/cli
sanity init

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

Terminal window
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 连接器#

安装必要依赖:

Terminal window
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 结合,你拥有了一个兼具“静态网站性能”和“动态内容管理灵活性”的架构。

使用 Sanity CMS + Next.js 构建高性能内容驱动型应用
https://sw.rscclub.website/posts/sanitycmsnextjs/
作者
杨月昌
发布于
2020-04-28
许可协议
CC BY-NC-SA 4.0