网上有很多 blog 的模板,不管是 nextjs,nuxt 还是 astro ,gatsby,vitepress,都存在一个问题:自己写完发布的blog,自己再看比较麻烦,不能很好的集成到笔记软件,像Obsidian或 Notion 中。另外博客模板一般用 markdown,在代码库中写blog 没有在 Notion 或 Obsidian 中编辑体验好。最近折腾用Notion 的数据库作为 blog 的 内容管理系统 (CMS),网站用 nextjs 搭建,这样在Notion中写好的 blog,设置属性后,在网站上就能看到,编辑和发布都方便。
1 创建表格
在根目录创建一个表格数据库,之后再创建一些列,然后是创建一些视图,Notion 的布局视图有这几种,一般作为CMS,表格、列表和画廊布局都不错
2 拿到Notion 私有集成的token
第一次使用,在Notion 个人集成中https://www.notion.so/profile/integrations 添加内部集成,步骤截图如下:
类型选择 Internal 内部类型
配置好权限后保存,拷贝 集成密钥 以备后面使用
还可以在设置连接中,快速的找到连接,并复制token
3 接口测试
Notion 的开发文档中有接口详细信息
https://developers.notion.com/
他们提供了postman 接口调试的集合
https://www.postman.com/notionhq/notion-s-api-workspace/collection/y28pjg6/notion-api
主要用到2个接口,一是 根据数据的id ,查询有哪些页面,用作列表,二是根据 page id 查询 blocks, 用于具体博客内容的渲染
4 选择 支持 SSR 或SSG 的工具搭建网站
nextjs 是比较成熟的 SSR 方案,但是 nextjs 在部署的时候要启动一个渲染服务,对服务器的性能消耗 比 SSG 工具生成的 静态资源要多。我这里选择 vitepress,
主要是根据 **vitepress theme blog pure** 修改的,主要是两个地方,一个是 博文的索引,查询博文的 在 Notion 上的 page ID,还有属性信息;二是 一篇博文在 Notion 中的 所有 block 块信息,用第二个接口。
const apiHost = API_HOST
const databaseId = process.env.DATABASE_ID;
const notionToken = process.env.NOTION_TOKEN;
const url = `${apiHost}/databases/${databaseId}/query`;
const results = await fetch(url, {
method: 'POST',
headers: {
'Authorization': `Bearer ${notionToken}`,
'Content-Type': 'application/json',
'Notion-Version': '2022-06-28'
},
body: JSON.stringify({
"filter": {
"property": "状态",
"select": {
"equals": "发布"
}
},
"sorts": [
{
"property": "Last edited time",
"direction": "descending"
}
]
})
}).then(res => res.json()).then(data => {
return data?.results ?? []
}).catch(error => {
console.log('apierror')
console.error(error)
return error
})
博文全文的内容,要用到 vitepress 中的动态路由,在做SSG 构建的时候,要生成所有博文,以静态文件的方式存放
// [id].paths.js
export default {
async paths() {
const apiHost = process.env.API_HOST
const databaseId = process.env.DATABASE_ID
const notionToken = process.env.NOTION_TOKEN
const url = `${apiHost}/databases/${databaseId}/query`;
const results = await fetch(url, {
method: 'POST',
headers: {
'Authorization': `Bearer ${notionToken}`,
'Content-Type': 'application/json',
'Notion-Version': '2022-06-28'
},
body: JSON.stringify({
"filter": {
"property": "状态",
"select": {
"equals": "发布"
}
},
"sorts": [
{
"property": "Last edited time",
"direction": "descending"
}
]
})
}).then(res => res.json()).then(data => {
return data?.results ?? []
}).catch(error => {
console.error(error)
return error
})
let pageBlock = {};
for (const element of results) {
const id = element.id
const url = apiHost + `/blocks/${id}/children?page_size=100`;
let blocks = await fetch(url, {
method: 'GET',
headers: {
'Authorization': `Bearer ${notionToken}`,
'Content-Type': 'application/json',
'Notion-Version': '2022-06-28'
}
}).then(res => res.json()).then(data => {
console.log('get blocks success for pageid', id)
return data.results
}).catch(error => {
console.log('apierror')
console.error(error)
return error
})
pageBlock[id] = blocks
}
return results.map((pkg) => {
return {
params: {
id: pkg.id,
title: pkg.properties.Title?.title[0]?.plain_text ?? '888',
blocks: pageBlock[pkg.id]
},
page: {
title: pkg.properties.Title?.title[0]?.plain_text ?? '888',
blocks: pageBlock[pkg.id]
}
}
})
}
}
效果如下:
总结
Notion + Vitepress 搭建blog ,主要分两步,第一步在Notion 管理面板中新建 内部集成,设置权限,并保存token。 第二步用 SSG 工具 构建博客,并用 Nginx 代理生成的静态文件。 这样的组合,方便博文的编辑和收藏,也能根据需要定义blog 的主题样式。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。