基于Next.js与Notion API构建高性能静态博客全攻略
1. 项目概述用Notion驱动你的个人网站如果你和我一样既想拥有一个完全自定义、性能出色的个人博客或作品集网站又不想被繁琐的后台内容管理和数据库设计所束缚那么这个项目可能就是你的“梦中情栈”。Next.js Notion Starter Kit 的核心思路非常巧妙它把 Notion 这个我们日常用来记笔记、做规划的“瑞士军刀”变成了一个功能齐全的CMS内容管理系统。你只需要在 Notion 里像平时一样写文章、整理项目这个工具就能自动将它们变成一个高速、美观的静态网站。我最初接触这个方案是因为受够了传统博客平台如 WordPress的臃肿和主题开发的复杂性也尝试过一些“无头CMS”但总觉得为了管理几篇文章而维护一个独立的后台有些杀鸡用牛刀。Notion 的块编辑器体验极佳支持富文本、嵌入、数据库而且跨平台同步无缝。这个 Starter Kit 的出现完美地将 Notion 的内容创作体验与 Next.js 的现代前端开发能力结合了起来。它不仅仅是一个“玩具”像原作者 Travis Fischer 的个人网站 transitivebullsh.it 这样成熟的站点也完全基于此构建这证明了其生产可用性。简单来说这个工具适合以下几类人前端开发者希望快速搭建一个技术博客来展示作品和分享知识创作者或写作者希望拥有一个完全属于自己的、设计精美的发布平台而无需学习复杂的建站工具团队或个人需要一个小型的产品展示页或文档站并希望内容更新能像编辑文档一样简单。它的优势在于“内容归你呈现归我”——你享有 Notion 提供的极致自由的内容组织能力同时又能获得一个由 Next.js 加持的、在速度和SEO方面表现优异的现代化网站。2. 核心架构与设计思路拆解2.1 为什么是 Next.js Notion 这个组合这个组合的成功并非偶然它精准地击中了个人建站者的几个核心痛点。首先Next.js作为 React 的元框架提供了开箱即用的服务端渲染SSR、静态站点生成SSG、图像优化、API路由等能力。这意味着你的网站天生就具备优秀的首屏加载速度和搜索引擎友好性。对于个人站点来说SSG模式尤其合适在构建时一次性从 Notion 拉取所有数据并生成静态HTML文件部署后访问速度极快且几乎零服务器成本。其次Notion作为一个“全能型”工具其 API 暴露了页面和数据库的所有结构化数据。react-notion-x这个库扮演了关键角色它负责将 Notion API 返回的复杂块数据blocks渲染成高质量的 React 组件。这样一来Notion 中丰富的块类型——标题、列表、代码块、引用、表格、甚至内嵌的数据库视图——都能在网页上得到近乎原生的渲染。这个 Starter Kit 的设计哲学是“约定优于配置”。它没有试图创建一个复杂的后台或定义一套全新的内容模型而是完全拥抱 Notion 已有的数据结构。你的网站结构就是你 Notion 工作区的页面层级关系你的文章样式就是你在 Notion 里设置的样式。这种极低的迁移和学习成本是它最大的吸引力之一。2.2 数据流与渲染流程解析理解数据如何从 Notion 流动到用户浏览器对于后续的定制和问题排查至关重要。整个流程可以概括为以下几个步骤构建时数据获取在运行npm run build时Next.js 会执行getStaticProps和getStaticPaths函数。这些函数会调用 Starter Kit 封装的逻辑通过 Notion 官方 API需要集成或更常见的第三方 Notion API 客户端如notion-client根据你在site.config.ts中配置的rootNotionPageId递归地获取该页面及其所有子页面的数据。数据转换与缓存获取到的原始 Notion 数据会被处理并缓存。这里涉及到一个关键点Notion 的页面IDPage ID到友好URLSlug的映射。系统会自动根据页面标题生成一个 slug例如“My Awesome Post” - “my-awesome-post”并在生产环境中去掉冗长的页面ID使URL更简洁。静态页面生成Next.js 利用处理好的数据为每个页面生成对应的静态 HTML 文件。react-notion-x的组件负责将 Notion 块数据渲染成实际的 DOM 结构。同时一些增强功能如预览图片生成、社交元标签Open Graph创建也会在这个阶段完成。客户端水合生成的静态页面被发送到浏览器后React 会进行“水合”使页面变得可交互。搜索功能CMDK、深色模式切换、目录滚动监听等动态特性都在客户端激活。实时性考虑对于需要最新数据的场景比如评论功能可以通过 Next.js 的 API Routes 创建后端接口或者使用getServerSideProps进行服务端渲染。但就纯内容展示而言SSG 模式配合定期的重新部署例如通过 GitHub Actions 或 Vercel 的定时部署已经足够。这种架构带来的好处是显而易见的性能极致静态文件 CDN、安全性高无动态数据库、成本低廉托管在 Vercel 等平台有免费额度。唯一的“动态”部分——从 Notion 读取数据——也发生在构建阶段不会影响最终用户的访问速度。3. 从零开始的详细配置与部署指南3.1 环境准备与项目初始化首先你需要一个 Node.js 环境版本建议在 16 或以上。我推荐使用nvm来管理 Node 版本这样可以避免全局依赖冲突。# 使用 nvm 安装并切换 Node.js 版本 nvm install 18 nvm use 18接下来获取项目代码。最直接的方式是 Fork 原仓库到你的 GitHub 账户下这样你既能获得一个独立的起点也方便后续同步上游更新。# 克隆你 Fork 后的仓库 git clone https://github.com/你的用户名/nextjs-notion-starter-kit.git cd nextjs-notion-starter-kit安装项目依赖这里使用npm或yarn均可。npm install # 或 yarn install完成安装后不要急着运行。整个项目的配置核心只有一个文件site.config.ts。在动手修改它之前我们需要先搞定 Notion 端的设置。3.2 Notion 工作区与页面配置这是最关键的一步决定了你的网站能展示什么内容。创建一个公开页面在你的 Notion 工作区中创建一个新页面作为你网站的“根目录”。你可以直接复制原作者提供的 模板页面 也可以从头创建。这个页面将作为你网站的首页。获取页面ID进入你刚创建的页面在浏览器地址栏中你可以看到类似https://www.notion.so/你的工作区/7875426197cf461698809def95960ebf的链接。末尾的那一串字符7875426197cf461698809def95960ebf就是该页面的Page ID。复制它。设置页面为公开点击页面右上角的“分享”按钮然后打开“公开访问”开关。这样Starter Kit 才能通过 Notion API 读取到页面内容。可选获取工作区ID工作区IDSpace ID在某些高级配置中可能会用到。获取它的一个简单方法是在浏览器中打开你的公开 Notion 页面按 F12 打开开发者工具在 Console 标签页中输入window.block.space_id并回车控制台就会打印出你的 Space ID。实操心得我建议专门为这个网站创建一个新的 Notion 工作区或者至少使用一个独立的页面分支。避免将个人私密笔记与公开网站内容混在一起便于管理。另外Notion 页面的图标和封面图会被自动用作网站的 Favicon 和 Open Graph 图片所以精心挑选一下会让你的站点看起来更专业。3.3 核心配置文件site.config.ts详解现在打开项目根目录下的site.config.ts文件。这个文件定义了网站的几乎所有元信息。我们逐项进行配置// site.config.ts import { SiteConfig } from ./src/types export const siteConfig: SiteConfig { // 1. 基础信息 name: 我的技术博客, // 网站名称会显示在标题和页脚 domain: www.myblog.com, // 你的域名用于生成绝对URL author: 你的名字, // 作者名 // 2. Notion 核心配置 rootNotionPageId: 7875426197cf461698809def95960ebf, // 替换为你复制的根页面ID rootNotionSpaceId: null, // 可选如果你知道你的 Space ID 可以填在这里 // 3. 基础功能开关 isPreviewImageSupportEnabled: true, // 是否启用预览图生成建议开启但首次构建慢 isRedisEnabled: false, // 是否使用 Redis 缓存预览图初期可关闭 // 4. SEO 与社交 description: 这是我的个人博客分享技术思考和项目经验。, // 网站描述 socialImageTitle: 我的技术博客, // 社交图片上显示的标题 socialImageSubtitle: 探索代码与创意, // 社交图片上显示的子标题 // 5. 页面相关 pageUrlOverrides: null, // 自定义页面URL映射高级功能 navigationStyle: default, // 导航样式 navigationLinks: [ // 自定义导航链接 { title: 关于, pageId: 关于页面的ID }, { title: 项目, pageId: 项目数据库页面的ID } ] }重点参数解析rootNotionPageId必须正确填写否则网站无法获取内容。isPreviewImageSupportEnabled强烈建议开启。它会为文章中的图片生成低质量占位符LQIP实现图片加载时的模糊到清晰效果极大提升体验。但注意首次构建时需要为每张图片生成这个占位符如果文章图片很多构建时间会很长。isRedisEnabled如果你开启了预览图支持并且网站内容较多构建时间让你难以忍受那么可以启用 Redis。它会缓存生成的预览图后续构建时直接读取缓存速度飞快。对于个人博客如果更新不频繁可以暂时关闭。3.4 本地运行与调试配置完成后就可以在本地启动开发服务器了。npm run dev访问http://localhost:3000你应该能看到你的 Notion 根页面内容被渲染成了网站。开发环境下的URL会包含 Notion 页面ID例如/my-home-page-d1b5dcf8b9ff425b8aef5ce6f0730202这是为了方便调试。在本地开发时你可以实时热重载修改site.config.ts或 React 组件页面会即时更新。查看Notion数据在页面上右键“检查”在开发者工具的“网络”选项卡中可以找到对/_notion/的请求查看从 Notion 获取的原始数据对于调试数据问题很有帮助。测试功能尝试搜索CMDK、切换深色模式、查看自动生成的目录是否正常工作。3.5 部署到 VercelVercel 是这个项目推荐的部署平台因为它与 Next.js 同出一源集成度最高并且提供了非常慷慨的免费套餐。推送代码将你修改后的代码提交并推送到你的 GitHub 仓库。git add . git commit -m 初始配置 git push origin main导入到 Vercel登录 Vercel 点击“New Project”从 GitHub 导入你刚才推送的仓库。配置项目Vercel 会自动检测到这是一个 Next.js 项目。在配置页面你通常不需要修改任何构建设置。直接点击“Deploy”。关键设置关闭部署保护部署完成后有一个至关重要的步骤。进入 Vercel 项目的 “Settings” - “Deployment Protection”。确保 “Vercel Authentication” 是关闭状态。如果这个选项是开启的那么社交媒体爬虫如 Twitter、Facebook 的机器人在尝试抓取你网站为分享文章生成的预览图时会遇到 401 未授权错误导致分享链接没有图片。这是新手最容易踩的坑。配置自定义域名可选在 “Settings” - “Domains” 中添加你购买的域名并按照指引配置 DNS 解析记录。部署成功后你的网站就上线了Vercel 会自动为每次向main分支的推送触发新的部署实现持续集成。4. 高级功能定制与优化实践4.1 自定义样式与主题虽然 Starter Kit 提供了不错的默认样式但要让网站真正具有个人特色样式定制是必须的。所有的核心样式都集中在styles/notion.css这个文件中。react-notion-x为每个 Notion 块都生成了一个唯一的 CSS 类名格式为.notion-block-{pageId}。这给了我们极其精细的控制能力。例如你想隐藏某个特定的块/* 在 styles/notion.css 末尾添加 */ .notion-block-260baa77f1e1428b97fb14ac99c7c385 { display: none; }更常见的需求是修改全局样式比如字体、颜色、间距。你可以通过覆盖react-notion-x提供的 CSS 变量来实现。在styles/globals.css或styles/notion.css的开头添加:root { /* 修改默认字体 */ --notion-font: Inter, -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, sans-serif; /* 修改浅色主题背景色 */ --bg-color: #fafafa; /* 修改深色主题背景色 */ --bg-color-dark: #1a1a1a; /* 修改代码块主题 */ --notion-code-background: #f6f8fa; }注意事项修改样式时建议使用浏览器的开发者工具先定位到目标元素的类名再进行覆盖。由于 CSS 优先级的问题有时可能需要使用!important来强制生效但应尽量避免优先通过提高选择器特异性来解决。4.2 优化图片加载预览图与 Redis 缓存图片是影响网站性能的最大因素之一。这个项目通过next/image组件和lqip-modern库实现了现代化图片优化。next/image自动提供图片的懒加载、按视口尺寸裁剪、WebP格式转换如果浏览器支持等功能。lqip-modern在构建时为每张图片生成一个极小的、模糊的 Base64 编码预览图。图片加载时先显示这个模糊预览图待原图加载完成后再平滑过渡这就是所谓的“模糊到清晰”效果。启用 Redis 缓存 如果你的网站有大量图片每次构建都重新生成预览图会非常耗时。启用 Redis 可以缓存这些生成的预览图。获取 Redis 服务你可以使用 Upstash 或 Redis Labs 等云服务商它们都提供免费的 Redis 实例。配置环境变量在 Vercel 项目的 “Settings” - “Environment Variables” 中添加REDIS_HOST和REDIS_PASSWORD或REDIS_URL具体取决于你的 Redis 提供商给你的连接字符串格式。修改配置将site.config.ts中的isRedisEnabled设为true。本地开发在项目根目录创建.env.local文件填入相同的REDIS_HOST和REDIS_PASSWORD以便本地构建也能使用缓存。# .env.local REDIS_HOSTyour-redis-host.upstash.io REDIS_PASSWORDyour-redis-password完成以上步骤后首次构建仍然会慢因为需要生成并填充缓存。但从第二次构建开始速度就会有质的飞跃。4.3 实现自定义页面路由与导航默认情况下页面的URL由 Notion 页面标题自动生成。但有时我们想要更简洁或特定的URL。方法一使用Slug属性推荐在你的 Notion 数据库或作为数据库的页面中为每篇文章添加一个属性属性类型为“Text”名称就叫做Slug。在这个属性里填写你想要的URL路径例如my-first-post。系统会优先使用这个Slug值而不是页面标题来生成URL。方法二使用pageUrlOverrides配置在site.config.ts中你可以直接映射特定的 Notion 页面ID到自定义路径。export const siteConfig: SiteConfig { // ... 其他配置 pageUrlOverrides: { // Notion页面ID: 自定义路径 dfc7f709-ae3e-42c6-9292-f6543d5586f0: /about-me, a1b2c3d4e5f6: /projects/2024-ai-tool } }自定义导航栏navigationLinks配置项允许你在网站头部添加自定义链接。这些链接可以指向你 Notion 工作区内的其他页面。navigationLinks: [ { title: 首页, pageId: 你的根页面ID }, { title: 所有文章, pageId: 你的文章数据库页面ID }, { title: 关于, pageId: 关于页面ID }, { title: GitHub, url: https://github.com/你的用户名 } // 也支持外部链接 ]4.4 集成数据分析与评论系统一个完整的博客需要了解访问情况和与读者互动。数据分析 项目内置支持 Fathom 和 PostHog 两种轻量级分析工具。以 Fathom 为例注册 Fathom 并创建一个新站点获取站点ID。在 Vercel 环境变量中添加NEXT_PUBLIC_FATHOM_ID值为你的站点ID。重新部署项目。Fathom 的统计脚本将自动注入到你的网站中。评论系统 Starter Kit 本身不包含评论功能但我们可以轻松集成第三方服务如 Giscus基于 GitHub Discussions或 Utterances基于 GitHub Issues。以 Giscus 为例按照 Giscus 官网指引进行配置获取一段脚本代码。在项目中创建一个客户端组件例如app/components/Giscus.tsx使用useEffect在组件挂载后动态加载 Giscus 脚本。在你的文章页面模板例如app/[pageId]/page.tsx中引入这个Giscus组件。你可以通过判断页面的properties中是否有“允许评论”的复选框属性来决定是否在特定文章下显示评论框。5. 常见问题排查与性能优化实录在实际使用中你肯定会遇到一些问题。下面是我在搭建和维护过程中遇到的一些典型情况及其解决方案。5.1 构建失败与数据获取错误问题构建时卡住或报错提示 Notion API 相关错误。可能原因1页面未公开。这是最常见的原因。请务必回到 Notion确认你设置的rootNotionPageId对应的页面以及它所有子页面的分享权限都是“公开”。可能原因2网络问题。Notion API 在国内访问可能不稳定。尝试在site.config.ts中配置一个代理或者使用云构建环境如 Vercel 本身。可能原因3API 速率限制。如果你一次性获取的页面非常多可能会触发 Notion API 的速率限制。可以考虑分批次构建或者为notion-client增加重试逻辑。问题本地运行正常部署到 Vercel 后页面空白或样式错乱。排查步骤检查 Vercel 的部署日志。在 Vercel 项目控制台的 “Deployments” 标签页点击最新的部署查看构建日志。错误信息通常会在这里显示。检查环境变量。确认在 Vercel 中设置的环境变量如REDIS_HOST名称和值是否正确。检查site.config.ts。确保其中没有引用本地路径或仅在本地存在的资源。5.2 样式与布局问题问题Notion 中的某些内容如特定类型的数据库视图、复杂布局渲染不正常或丢失。原因与解决react-notion-x虽然强大但并未 100% 支持所有 Notion 块类型。一些非常新的或复杂的块如 Synced Block、某些高级数据库视图可能渲染不佳。解决方案通常是在 Notion 中简化该部分内容的格式或者通过自定义 React 组件来覆盖特定块类型的渲染逻辑。你可以查阅react-notion-x的文档了解如何注册自定义渲染器。问题移动端布局异常。解决项目默认是响应式的但如果你添加了自定义样式可能会破坏响应式布局。使用 Chrome 开发者工具的“设备工具栏”进行移动端调试确保你的自定义 CSS 使用了相对单位如rem,%,vw而非绝对单位如px并合理运用媒体查询media。5.3 性能优化 checklist当你的网站文章越来越多时以下优化可以保持其速度启用 Redis 缓存如前所述这对缩短构建时间至关重要。优化图片源Notion 托管的图片有时加载较慢。可以考虑使用 Next.js 的next/image配置一个自定义的图片加载器或者将图片迁移到更快的 CDN如 Cloudinary、Imgix但这需要修改react-notion-x的图片渲染逻辑属于高级定制。增量静态再生对于更新不频繁的页面如关于页可以在getStaticProps中设置一个较长的revalidate时间例如一天减少不必要的重复构建。代码分割确保你引入的第三方库如图表库、特定组件库都被正确地进行代码分割不要全部打包到主 bundle 中。分析 Bundle 大小使用next/bundle-analyzer分析生产环境的打包文件找出体积过大的模块并优化。5.4 内容管理与 SEO 最佳实践利用 Notion 数据库进行内容管理不要只用简单的页面列表。创建一个“文章”数据库为每篇文章添加“发布日期”、“标签”、“摘要”、“状态”草稿/已发布等属性。这样你可以在网站上轻松实现按标签筛选、按日期归档等功能。Starter Kit 可以很好地渲染数据库的“列表视图”或“画廊视图”作为文章索引页。优化 SEO项目已自动生成基础的 Open Graph 和 Twitter Card 标签。你还可以在site.config.ts中完善description。为重要的页面在 Notion 页面属性中添加“Description”字段并在代码中读取该字段作为页面的专属meta description。确保网站的sitemap.xml和robots.txt正确生成可能需要额外配置 Next.js 的rewrites或自定义 API 路由。处理重复标题如果 Notion 中有两个页面标题相同它们生成的 slug 也会相同导致构建错误。系统会报错提示你。解决方法就是修改其中一个页面的标题或者使用前面提到的Slug属性或pageUrlOverrides来手动指定不同的路径。我个人在深度使用这个 Starter Kit 近一年后最大的体会是它完美平衡了“自由度”和“便利性”。你无需关心服务器、数据库运维又能获得一个性能顶尖、设计可控的网站。它尤其适合那些内容驱动、更新频率适中、且开发者希望专注于内容创作而非工具维护的场景。当然它也不是万能的对于需要高度复杂交互或实时数据的应用还是需要更传统的全栈方案。但对于一个个人博客、作品集或知识库来说它提供的方案已经足够优雅和强大。