发布于2026年3月18日

我在 48 小时内搭建了一个 Next.js + Sanity CMS 网站 — 这些方法真正有效

一份真实的构建日记:使用 Sanity CMS、Tailwind CSS 4 部署 Next.js 16 生产网站到 Vercel。没有废话——只有节省数小时的决策、错误和捷径。

作者:Frank Yao

摘要

我在不到 48 小时的实际构建时间内搭建了一个使用 Sanity CMS 的 Next.js 16 App Router 网站。最省时的做法包括:跳过 create-next-app 默认的 Tailwind(它安装的是 v3 而非 v4)、除了移动端导航外全部使用 Server Components,以及将 Sanity Studio 单独部署而不是嵌入。最大的失误:没有从第一天就定义模块化的 schema 对象。以下是完整的分析。

我在 48 小时内搭建了一个 Next.js + Sanity CMS 网站 — 这些方法真正有效
Frank Yao

快速参考:已上线的技术栈

在深入探讨之前,这里是我使用的具体技术以及每个组件的重要性:

Next.js 16.1 (App Router) — 默认使用服务器组件,这意味着向浏览器传输更少的 JavaScript。Tailwind CSS 4.2 — 采用 CSS 优先配置,使用 @theme 块替代旧的 tailwind.config.js。Sanity 5.x — 无头 CMS,具备实时协作编辑和 GROQ 查询语言。Motion 12 — 动画库,从 motion/react 导入,而非旧的 framer-motion 包。Vercel — 零配置部署,自动集成 Git。

为什么我停止修复旧站点并重新开始

之前版本的 frankyao.com 是一个基于设计模板构建的静态 HTML 站点。表面看起来还不错,但底层呢?内部路由失效、CTA 按钮无任何跳转、联系表单没有后端支持,SEO 价值为零。每个页面的 meta 标题都相同。站点地图列出了不存在的页面。

我本可以修补它。在这里添加一个表单处理程序,在那里修复一个失效链接。但当你在一个根本性损坏的基础上不断打补丁时,你只是在创造日后需要偿还的技术债务。我花在调试别人混乱代码上的时间,不如用来从头构建一个干净的项目。

没人警告你的 Create-Next-App 陷阱

有一件事第一次遇到时浪费了我一个小时:npx create-next-app@latest --tailwind 仍然安装的是 Tailwind v3.4。不是 v4。在 2026 年 3 月。--tailwind 标志会生成一个 tailwind.config.js 文件并使用旧的 @tailwind 指令。如果你计划使用 Tailwind 4 的 CSS 优先 @theme 块(你应该用——它们更快更简洁),你需要在不使用 --tailwind 的情况下创建项目脚手架,然后手动安装 v4。

解决方法很直接:运行 create-next-app 时不带 tailwind 标志,然后执行 npm install tailwindcss @tailwindcss/postcss postcss。创建一个包含 @tailwindcss/postcss 插件的 postcss.config.mjs。然后在 globals.css 内的 @theme 块中定义你的设计令牌。不需要 JavaScript 配置文件。

服务器组件改变了我对导航的思考方式

在旧的 React 思维模型中,你的导航组件需要 useState 来实现移动端菜单切换,因此整个组件变成客户端组件。这意味着仅为渲染一个链接列表就要向浏览器传输 React。使用 Next.js 16 的 App Router,我采用了不同的拆分方式:Nav 组件保持为服务器组件(零客户端 JavaScript),只有 MobileNav 汉堡菜单切换是一个独立的客户端组件。导航链接、徽标、桌面布局——全部在服务器端渲染。只有交互部分使用 'use client'。

这种模式——带有客户端组件孤岛的服务器组件父组件——是现代 Next.js 中最大的性能优势。我的初始页面加载从 127KB 的 JavaScript 减少到不到 40KB。

会困扰你的 Sanity Schema 错误

当我第一次为客户项目设置 Sanity 时,我创建了扁平化 schema。每个文档类型都有自己的 SEO 字段、自己的图片配置、自己的富文本设置。六个月后,我需要为每个内容类型添加 Open Graph 图片支持。这意味着要编辑 8 个不同的 schema 文件。

对于 frankyao.com,我从第一天起就构建了模块化 schema 对象。一个被 blogPost 和 portfolioItem 同时引用的 seoFields 对象。一个具有一致富文本配置的 portableTextBody 对象。一个在任何需要 FAQ 部分的地方重用的 faqItem 对象。当我需要向 SEO 配置添加字段时,我只需更改一个文件,每个内容类型都会继承它。

下次我会做的不同之处

我会在第一次构建时跳过页面过渡效果。App Router 退出动画所需的 FrozenRouter 模式从 Next.js 内部 API (LayoutRouterContext) 导入,可能在版本之间发生破坏。滚动显示动画?它们使用稳定的 whileInView API,从第一天起就值得实现。但跨页面淡入淡出过渡增加了复杂性,而这种微妙的视觉效果大多数用户不会有意识地注意到。

我还会立即设置用于 ISR 缓存失效的 Sanity webhook,而不是作为第 8 阶段的任务。在生产环境中等待 60 秒才能看到内容更改,在开发过程中很烦人。

常见问题

Next.js 16 在生产环境中是否足够稳定?

是的。Next.js 16.1 自 2026 年初以来一直很稳定。App Router 不再是实验性功能——它是默认且推荐的方式。Server Components、metadata API 和图像优化在生产环境中都能可靠运行。

应该使用 Tailwind CSS 4 还是继续用 v3?

新项目使用 v4。CSS 优先的 @theme 配置构建更快,输出更小,且不需要 JavaScript 配置文件。继续使用 v3 的唯一理由是维护现有项目且大量使用了自定义插件。

为什么要单独托管 Sanity Studio 而不是嵌入 Next.js?

将 Sanity Studio 嵌入 Next.js 应用会使内容编辑环境与前端部署耦合。如果网站构建失败,就无法编辑内容。独立的 Studio 部署在 *.sanity.studio 上,独立部署且始终可用。

这个技术栈的运行成本是多少?

对于个人品牌网站:基本上每月 $0。Vercel 免费套餐可处理托管。Sanity 免费计划包含 500 万次 CDN 请求和 1 万个文档。唯一的成本是域名(约每年 $12)。

准备好付诸行动?

让我们聊聊 AI 自动化和智能数字策略如何为你的业务带来实际成果。