- UI组件
- 前端
【免费下载链接】react-notion-x
Fast and accurate React renderer for Notion. TS batteries included. ⚡️
导读
在 react-notion-x 生态中,notion-x-to-md 负责把 Notion 页面转换为 GitHub Flavored Markdown(GFM),是让 Notion 内容进入 LLM 上下文、构建知识库或静态博客的常用桥梁。本文以仓库中的 Checklists 转换示例 为线索,完整讲解 Notion 待办清单(to_do块)如何被渲染为- [x]/- [ ]任务列表,并深入源码剖析其判定逻辑、类型约束与快照测试,最后给出可直接运行的调用与 CLI 方案。读完你将掌握:待办清单块的转换规则、notionPageToMarkdown的完整调用链,以及如何用一条命令把任意公开 Notion 页面转成 Markdown。
一、示例文档还原:to_do块的转换输出
仓库中的 38fa73d49b8f40aab1f3f8c82332e518.md 是一个专门用于验证待办清单转换能力的示例页面,其转换结果如下:
# Checklists > This block type is called `to_do` - [x] Pretty URLs - [x] Custom domains - [x] Google Fonts - [x] Page title/description for SEO - [x] Custom scripts - [x] A setup wizard to customize the script (instead of having to change the raw code) - [ ] Stop random pages from showing up under custom domain - [ ] Hide the What's New banner这个输出揭示了三条关键事实:
- 页面标题被渲染为 H1:
# Checklists来自页面的 title 属性; - 引用块被渲染为 GFM 引用:
> This block type is called to_do对应 Notion 中的 quote 块; - 每个待办项都被渲染为 GFM 任务列表项:已勾选输出
- [x],未勾选输出- [ ]。
该页面在 readme.md 的示例索引表 中被标记为Checklists / Supported ✅,页面 ID 为38fa73d49b8f40aab1f3f8c82332e518,与当前文档文件名一致。
二、源码级剖析:to_do块如何变成- [x]
2.1 渲染入口:renderBlock的to_do分支
notion-x-to-md 的核心渲染函数是 src/block.ts 中的renderBlock,它接收(blockId, recordMap, level),先从recordMap.block中取出原始块数据,再根据块的type字段分发到对应分支。待办清单的分支位于 src/block.ts#L98-L102:
case 'to_do': { const checked = (block as any).properties?.checked?.[0]?.[0] === 'Yes' const checkbox = checked ? '- [x]' : '- [ ]' return `${checkbox} ${getTitle(block, recordMap)}` }这段实现非常简洁,却包含了完整的状态判定逻辑:
- 取勾选状态:
block.properties?.checked是一个二维数组,[0][0]取到的是单元格中的第一个 token。当该值严格等于字符串'Yes'时判定为已勾选; - 映射为 GFM 语法:已勾选输出
- [x],未勾选输出- [ ],这是 GitHub Flavored Markdown 任务列表(task list)的标准写法; - 拼接标题文本:
getTitle在 src/block.ts#L398-L400 中实现,它调用decorationsToMarkdown(block.properties?.title ?? [], recordMap),将标题的富文本 decoration 还原为 Markdown 文本(粗体、斜体、链接、@提及等都会被正确还原)。
2.2 类型约束:TodoBlock的数据结构
to_do块的类型定义位于 packages/notion-types/src/block.ts#L244-L251:
// TODO export interface TodoBlock extends BaseTextBlock { type: 'to_do' properties: { title: Decoration[] checked: (['Yes'] | ['No'])[] } }可以看到:
BlockType联合类型中注册了'to_do'(见 packages/notion-types/src/block.ts#L15);checked属性被严格建模为(['Yes'] | ['No'])[],这与渲染端=== 'Yes'的判定完全吻合;- 每个待办项都拥有独立的
title(Decoration 数组)与checked状态,因此同一个清单里已勾选与未勾选项可以混合出现,正如示例文档展示的 6 项[x]+ 2 项[ ]。
2.3 与 React 渲染端的对照验证
同一块类型在 react-notion-x 的 React 渲染端 src/block.tsx#L800-L821 中也有对应实现:
case 'to_do': { const isChecked = block.properties?.checked?.[0]?.[0] === 'Yes' return ( <div className={cs('notion-to-do', blockId)}> <div className='notion-to-do-item'> <components.Checkbox blockId={blockId} isChecked={isChecked} /> ...两个渲染端采用了完全相同的判定表达式checked?.[0]?.[0] === 'Yes',可以确认这是 react-notion-x 生态中处理待办状态的事实标准。差别只在于输出形态:React 端渲染为带勾选框的 DOM(样式见 packages/react-notion-x/src/styles.css#L2199 的notion-to-do-checked规则),Markdown 端则映射为- [x]/- [ ]。
三、调用链与用法:如何复现这份输出
3.1 编程方式调用
示例输出的完整生成链路是:NotionAPI.getPage拉取页面 →notionPageToMarkdown递归渲染所有块。notionPageToMarkdown定义在 src/notion-page-to-markdown.ts#L17-L25:
export async function notionPageToMarkdown( recordMap: ExtendedRecordMap ): Promise<string> { const rootBlockId = Object.keys(recordMap.block)[0] if (!rootBlockId) return '' const markdown = await renderBlock(rootBlockId, recordMap) return markdown.trim() }函数以recordMap.block的第一个 key 作为根页面块,调用renderBlock递归渲染整棵块树,最后trim()去除首尾空白。值得注意的是它必须为async——因为渲染过程中可能拉取远程资源(如 tweet 嵌入,见 tweet 分支)。子块通过renderBlockChildren以p-map并发(concurrency: 4)渲染,见 src/block.ts#L379-L396。
完整的可运行示例(摘自 packages/notion-x-to-md/readme.md#L27-L40):
import { NotionAPI } from 'notion-client' import { notionPageToMarkdown } from 'notion-x-to-md' const api = new NotionAPI() // fetch a notion page's content const page = await api.getPage('38fa73d49b8f40aab1f3f8c82332e518') // convert the page to a markdown string const markdown = await notionPageToMarkdown(page) console.log(markdown)要点:
- 无需 API Key:不要求创建 Notion 官方 API 集成,只要页面是公开可访问的即可(见 readme.md 的 Notes);
- 输出为 GFM:
notion-x-to-md明确输出 GitHub Flavored Markdown,这对 LLM 的解析尤为友好; - Node 版本要求:
engines.node >= 18(见 package.json)。
3.2 CLI 一行命令
除编程调用外,包还内置了 CLI(bin字段指向 src/cli.ts,由 commander 实现)。直接用npx运行即可:
npx -y notion-x-to-md https://notion.so/38fa73d49b8f40aab1f3f8c82332e518或直接传页面 ID:
npx -y notion-x-to-md 38fa73d49b8f40aab1f3f8c82332e518CLI 的完整用法(摘自 readme.md):
Usage: notion-x-to-md [options] <page> Converts a Notion page to Markdown Arguments: page Notion page ID or URL (must be publicly accessible) Options: -h, --help display help for command<page>参数既支持完整 URL,也支持不带连字符的 32 位页面 ID,由NotionAPI.getPage统一解析。
3.3 安装方式
npm install notion-x-to-md该包以notion-client、notion-types、notion-utils为 workspace 依赖(见 package.json),构建工具为 tsdown,测试使用 vitest + typecheck。
四、测试与快照:示例文档是持续集成的产物
examples/38fa73d49b8f40aab1f3f8c82332e518.md并非手写文档,而是测试管线自动生成的产物。src/notion-page-to-markdown.test.ts 中的测试会:
- 用
new NotionAPI().getPage(id)拉取真实公开页面; - 调用
notionPageToMarkdown转换; - 断言输出非空、首尾无多余空白,并与快照比对。
测试文件中的writeExamples开关(test 文件 L32-L49)在开启时会把转换结果写入examples/<pageId>.md,因此该目录下的每个.md文件都可以视为一个"渲染正确性快照"。
对应的快照位于 src/snapshots/index.test.ts.snap#L469-L483:
exports[`notionPageToMarkdown success 38fa73d49b8f40aab1f3f8c82332e518 1`] = ` "# Checklists > This block type is called \`to_do\` - [x] Pretty URLs ...快照内容与 examples 目录 完全一致,从测试角度再次证实:只要 Notion 页面结构不变,to_do块的 Markdown 输出就是稳定、可预期的。
五、相关设计细节与注意事项
5.1 状态语义:'Yes'字符串的来由
Notion 私有 API 中,勾选框类属性的原始值就是字符串'Yes'/'No'(这一点在集合(database)属性渲染中同样成立,见 src/property.ts#L35-L38 中 checkbox 属性渲染为✓/✗的逻辑)。因此转换器直接与原始数据比对,不经过任何布尔转换,判定唯一且无歧义。
5.2 待办项的富文本
to_do分支中的getTitle复用了通用标题渲染逻辑,因此待办项文本内可以包含粗体、斜体、删除线、行内代码、链接、页面引用、@ 提及、日期等所有 text.ts 支持的 decoration 类型,它们都会被还原为对应 Markdown 语法后再拼接到- [x]/- [ ]之后。
5.3 适用范围与限制
- 仅支持公开可访问的 Notion 页面;
- Notion 托管的临时图片 URL 在一段时间后会失效(与官方 Notion 应用行为一致),如需永久链接可对
getPage返回的ExtendedRecordMap做后处理,将临时图片上传至永久 URL 并保存 block ID 到 URL 的映射(见 readme.md 的 Notes); - 集合(database)会被统一渲染为 Markdown 表格,所有视图类型一视同仁。
六、小结
围绕 Checklists 示例 这一最小但完整的样例,可以梳理出一条清晰的转换链路:
- 数据来源:
NotionAPI.getPage拉取ExtendedRecordMap,其中to_do块携带title与checked('Yes'/'No')属性; - 判定规则:
checked?.[0]?.[0] === 'Yes'(block.ts#L99 与 notion-types block.ts#L249 双重印证); - 输出形态:
- [x] 文本/- [ ] 文本,即标准 GFM 任务列表,天然被 GitHub 与主流 LLM 良好解析; - 可验证性:快照测试保证了输出的确定性,examples 目录即测试产物。
对于任何需要"把 Notion 待办清单接入 AI 工作流"的开发者,npx -y notion-x-to-md <页面ID>已经是一条足够可靠的最小路径;而当你需要把勾选状态、富文本样式或自定义映射融入业务逻辑时,renderBlock的to_do分支则是理想的改造锚点。
- UI组件
- 前端
【免费下载链接】react-notion-x
Fast and accurate React renderer for Notion. TS batteries included. ⚡️
相关推荐
notion-x-to-md 代码块转换全解析:从 Notion Code Block 到 GitHub 风格 Markdown
notion x to md 代码块转换全解析:从 Notion Code Block 到 GitHub 风格 Markdown 本篇指南以 react not
UI组件前端react-notion-x 的 notion-x-to-md 集合数字格式化渲染实战:从 Notion 数据到 Markdown 表格
react notion x 的 notion x to md 集合数字格式化渲染实战:从 Notion 数据到 Markdown 表格 导读 本文围绕 not
UI组件前端react-notion-x 系列实战:用 notion-x-to-md 将 Notion 页面转换为 Markdown,喂给 LLM 的完整方案
react notion x 系列实战:用 notion x to md 将 Notion 页面转换为 Markdown,喂给 LLM 的完整方案 这篇指南围绕
UI组件前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考