基于Next.js和Notion Public API构建的博客系统,支持在Notion中嵌入MDX代码来实现更加丰富的效果。
使用docker快速部署。
.env
文件,参考 env.exampledocker-compose up -d
http://localhost:3010
。code
块pdf
块bookmark
、link-preview
和video
块(Notion仅返回URL,不含Open Graph信息)equation
块NOTION_TOKEN
和NOTION_DATABASE_ID
。npm install
.env
文件,填入NOTION_TOKEN
和NOTION_DATABASE_ID
NOTION_TOKEN=
NOTION_DATABASE_ID=
# for supabase
NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_ANON_KEY=
# 本地开发
npm run dev
# 生产环境构建与启动
npm run build
npm run start
打开http://localhost:3000即可在浏览器中查看结果。
为何选用Notion作为内容编辑器? 本人已有多年使用Notion的习惯,以前博客的做法是将用Notion写好后再copy到Markdown等编辑器,然后使用hexo发布。这样流程会非常长,而且需要转换为markdown格式,流程非常的不方便。所以直接使用Notion作为CMS,写好的内容可以直接发布。也不需要修改后的频繁同步。
为何要重造轮子,而不是直接使用react-notion-x
等已有的能力实现。
原因主要是git上大部分实现都是基于Notion非公开的API,存在以下缺陷:
大多数常见的块类型都受支持。但是,Public API中不支持某些块的信息,因此我们提供了简化的渲染。
Block Type | Supported | Notes |
---|---|---|
Paragraph | ✅ Yes | |
Headings | ✅ Yes | |
Bookmark | ✅ Yes | Use unfurl.js |
Bulleted List | ✅ Yes | |
Callout | ✅ Yes | |
Child Databases | ✅ Yes | Use tanstack/table |
Child page | ✅ Yes | |
Code | ✅ Yes | Use shiki and MDX |
Column list and column | ✅ Yes | |
Embed | ✅ Yes | |
Equation | ✅ Yes | Use katex |
File | ✅ Yes | |
Image | ✅ Yes | No position、size info in API |
Link Preview | ✅ Yes | Use unfurl.js |
Mention | ✅ Yes | Only Date |
Numbered List | ✅ Yes | |
✅ Yes | ||
Quote | ✅ Yes | |
Synced block | ✅ Yes | |
Table | ✅ Yes | |
To do | ✅ Yes | |
Toggle blocks | ✅ Yes | |
Video | ✅ Yes | Use iframely |
Breadcrumb | ❌ Missing | Not planned |
Template | ❌ Missing | Not planned. |
Divider | ❌ Missing | API Unsupported. |
Table Of Contents | ❌ Missing | API Unsupported. |
image
, video
, bookmark
以及 link-preview
等类型的block,Notion API仅返回URL,没有渲染相关数据结构(如title、desciprtion、icon等)。所以需要自己寻求解决方案,此处选择了iframely作为替代。Notion官方也是采用iframely。
iframely需要付费,所以也采用了unfurl.js作为兜底,效果上会有差距。
.env
文件中设置。或者在vercel面板上设置。RENDER_MDX=true
且在notion的code block中设置语言为markdown
REDIS_URL="redis://localhost:6379"
,否则使用内存、文件缓存NEXT_DATACACHE_EXPIRE
,默认1小时。注意如果使用Notion存储了pdf、图片等文件,过期时间不要过长,否则文件链接可能过期。NOTION_NOTE_DATABASE_ID
. 如果不需要,可以屏蔽 site.ts中的入口。