Next.js 调用 Notion API 记录
踩坑集合
坑一方面来源于 Next.js,另一方面来源于 Notion API。当然,我自己才是最大的坑。
- Next.js 服务端渲染
- Notion API 数据过滤
- Notion Block 数据渲染
- Notion 临时图片过期
- Next.js Image 组件使用
- Notion 文章页面样式渲染
以上基本就是我踩的所有坑了,在介绍踩坑经验之前,还是简单的说一下项目的初衷。
初衷
最初是因为,我学了前端,然后就想了解后端,最初是做了一个基于 edge-tts 的语音转文字全栈项目 Rotts(前端 React + 后端 Flask),但这个项目很简单,后端基本就是请求 API,获取声音列表,然后将声音、音高、文字等信息传递给 edge-tts,等待声音返回,然后播放/下载就行了。后台感觉还没有怎么体验就感觉结束了。
所以,就想着找另外一个项目,继续学习下后端。首先想到的是 Node.js,调研过程中,看到了很多人推荐的 Next.js,也是基于 Node.js。那就一拍即合,我也想简单造一个轮子,做一个将 Notion 作为 CMS 的博客系统。视觉上一切从简,减少负担,着重于内容的渲染。
本来想着有 ChatGPT,不会的问问他就行了。结果 Next.js App 太新了,他的资料库里都没有,每次问他相关内容都回答的不够准确。
项目信息
- 名称: Brog
- 介绍: Next.js 构建,CMS 为 Notion 的简约博客系统
- 技术栈:React + Next.js + Typescript + TailwindCSS
- Github:https://github.com/yikZero/Brog
Next.js 的坑
重复请求
其实我在刚开始的获取数据的时候,就有疑问,我这边 fetch 一下,那边 fetch 一下。都是相同的数据,会不会多次请求,会很浪费呀?
为了这个,我也一直在将函数功能与请求分离开,传递好几个 props 就行……. 但其实至少在 React 里不用在意这个。
Passing data between a parent layout and its children is not possible. However, you can fetch the same data in a route more than once, and React will automatically dedupe the requests without affecting performance.
如果你 fetch 的链接和参数不变,那么你多次的请求,React 也会帮你合并成一次进行请求。所以也不用一直在组件之间转发 props,你就请求多次相同数据吧,没什么问题。React 会自行合并请求,不会多次重复请求,影响网络。
服务端组件
怎么样算是服务端组件呢,放在 app/
目录下的应该都属于服务端组件。我不知道是不是服务端组件的时候,我把我用到的 components、lib 文件目录,全部扔到 app/
…… 就为了服务端组件。
想让其变成客户端组件,那就加一个 use client
在顶部,那就会被识别为客户端组件。Next.js 官方推荐能服务端就服务端。
next/image 应用
Next.js 官方因为 LCP performance 的原因,优化了 img 元素的应用,推荐使用官方 Image。
具体使用方法可参照 Image Optimization
我以为会很简单喽,替换个名字就好,但是其要求我提供明确的高度和宽度。我动态获取的图片,我咋知道图片的高度和宽度呢。所以也就使用了奇技淫巧…….也是 stackoverflow 上的方案。
Notion-Client 的坑
数据获取
Notion 官方有 @notionhq/client,同时 react-notion-x 也有一个 notion-client。我是先了解到的 notion-client ,所以样式写完之后,尝试集成的是第三方实现的。
怎么说呢,notion-client 也挺好,提供一个公开的 NOTION_PAGE_ID
环境变量,即可获取到数据。但是获取到是全量数据,没办法跟官方的 API 一样根据字段名进行筛选的功能,所以整理数据会麻烦很多。这对于我这新手还是麻烦太多了…….毕竟,在 Notion 获取的数据是一层一层套娃的,每一个块都有其 ID,搞得我晕头转向。
最后也还是参考 notion-blog-nextjs 应用的官方 API,来获取到相对应的数据。
图片过期
Notion 官方提供的数据中的图片链接是 Amazon 临时链接,一个小时就会过期。然后就会导致图片挂了。
Vercel Cron: 很多人也会选择使用 Vercel cron 功能,每个小时重新构建渲染一下。但我觉得这也太浪费资源、太不环保了 (:
临时地址转化为永久地址: 方案的话可以参考 fix: solve linked img crash #524
PicGo 上传至又拍云: 因为我迁移过数据,Markdown 图片如果都是相对地址的话,简直是个灾难。所以,我现在就会选择通过 PicGo 上传至又拍云中,返回一个我的 CDN 地址。如果要迁移的话,那至少图片不会丢。