前排提醒:如果你是初学者/萌新的话。最方便的还是接触TypeCho、Wordpress这类博客框架。没有什么是最好的。只有最适合你的~
前情提要
我初中的时候开始就想自己做一个博客网站。这很酷。
我最开始接触到的是Hexo。Hexo会把你写的Markdown生成为静态网站,然后你就可以部署到Github Pages、Vercel了。
然后后面我慢慢接触到Wordperss。一发不可收拾,好多好看的主题,好多设置好多选项。我那个时候还买了一堆主题。博客没写多少,主题到换了不知道多少个。数据库炸了重建,Wordpress炸了重装、网站访问不了查CDN、反复关关开开。乐此不疲。
可它太重了。又重又慢。
于是初三的时候我接触到了TypeCho。她很美,很轻。不过主题很少。
我买了一个主题,也就开始写博客了。
后来我服务器换到阿里了。但域名没有续费。也就不能再用TypeCho了。
()启动!
这就正式开启了我的折腾之旅。也就是你现在看到的这个博客。 其实这个博客的版本还有2个版本,目前的版本是最新的。因为篇幅问题我就不再展开了。
那个时候我已经有了一点基础的前端知识。我就在想:
- 我希望不用服务器
- 我希望它更新快 写完我就可以看到
- 我希望它自由。我可以加任何我想加的东西
- 我希望它极其的轻。快。
要满足这些可谓是十分艰难的。
- 无服务器那我们可以用 Serverless(你可以把它想成不用买服务器,而是有人访问时,代码才运行。用的时候才付钱。也不需要你管服务器,或者24小时开着)。比如常见的 Vercel、Netlify
- 自由,那选一个前端框架,比如 Next.js
那怎么满足第二点呢?
在一次偶然的机会,我看到了 Next.js 的 ISR(Incremental Static Regeneration)。
前面说到Hexo会把你写的Markdown生成为静态网站,但问题就在于,它会把整个网站全部重新生成一遍然后再更新。这非常慢。ISR就解决了这个问题。
举个菜单的例子。
我现在有一整个菜单,这个菜单是固定的,我直接把预置菜热一下给用户就可以了。
但假如我要增删改查一道菜,我需要把菜单里面的菜全部重新做一遍。
ISR平时也是这样,平时给你预置菜,但菜单改了之后,你改多少,我就只更新你要改的那到菜。
下一个客人就可以立马吃到新菜了。
也就是它的中文翻译,叫“增量静态再生”。

ISR是SSG的升级版,它既有静态页面的速度,又可以按需升级。
那文章存哪呢?
好问题。
按理来说是需要一个数据库对吧。但这还是太复杂了。对我来说你还得建表。
所以存在 Git 似乎成了最好的选择。
- GitHub/Gitee 都是免费的
- 你甚至可以用 GitLab
我个人选择了 Gitee 因为在国内速度比较快。
那...编辑器呢
我用了 Obsidian

它原生支持 Markdown。而且你可以自定义主题。
我还用了Git插件用于自动推送到Gitee。

用了QuickAdd这个插件来绑定一个快捷键 Alt+P 来快速发布文章(我希望只有发布了网站上面才能看到)。

QuickAdd 脚本(点击展开)
使用方法:
打开插件设置页面,点一下Template按钮。选择Macro,随意填写一个名称然后新建。我这里写发布文章。
在你的Obsidian根目录下面创建一个scripts文件夹。
创建一个publish.js。
module.exports = async (params) => {
const {app} = params;
const file = app.workspace.getActiveFile();
if (!file) {
new Notice("没有打开文件喵");
return;
}
// 使用 Obsidian API 直接修改 frontmatter(最可靠)
try {
let isPublished = false;
await app.fileManager.processFrontMatter(file, (fm) => {
// 切换 publish 状态
if (fm.publish === true) {
fm.publish = false;
isPublished = false;
} else {
fm.publish = true;
isPublished = true;
}
});
// 显示对应的提示
if (isPublished) {
new Notice("已设置为发布力");
} else {
new Notice("已取消发布喵");
}
} catch (error) {
console.error("Error:", error);
new Notice("设置失败喵:" + error.message);
}
};
重启Obsidian。打开插件设置。
点开你新建的设置。在User Script里面选择publish。
把那个小闪电点亮。
在Obsidian的设置里面找到快捷键。在上面搜索“发布文章”,然后给他设置快捷键即可。
博客的设计
现在我们有了 Obsidian、Gitee、Next.js、Vercel。那怎么把它们连起来呢?
最简单的想法是:
我在 Obsidian 写完文章,Git 推送到 Gitee,然后手动去 Vercel 点"重新部署",等 5 分钟构建完成,网站更新了。
但这太蠢了,而且ISR根本就没用上。
所以我用了 Webhook。
Webhook 简单说就是 Gitee 在收到你的推送后,会自动发个请求到你指定的网址。
我在 Vercel 这边写了一个 API 路由(/api/webhook/gitee),专门接收 Gitee 的推送通知。
收到通知后,先验证签名确保是 Gitee 发来的而不是别人乱发的,然后看看改了哪些文件(Gitee 会告诉你),只处理 Markdown 文件,接着从 Gitee 拉取文件内容,解析 Markdown 转成 HTML。

但图片是个大问题。
Obsidian 里的图片是本地的,比如 ![[image.png]]。但网站访问不到你电脑上的图片。
所以需要把图片上传到 CDN。我用的是 DogeCloud OSS。
这部分有个巧妙的地方。
扫描 Markdown 找出所有图片引用,从 Gitee 下载图片,计算图片的 MD5(内容哈希)。
然后用这个哈希生成一个文件名,比如 abc123.png,拼接上 CDN 域名就得到了最终的 URL。
关键是这个 URL 是确定的,因为哈希是确定的。
所以我不用等图片上传完成,就可以先把 Markdown 里的图片链接替换掉,然后立即返回给用户。
图片呢?扔到后台慢慢上传。不阻塞。
这样做的好处是快。用户看到新文章不用等图片上传完。而且相同内容的图片只会上传一次,图片 URL 永远不变(因为哈希不变),可以充分利用 CDN 缓存。

为了速度,我用了多层缓存(这是可选的)。
Redis 缓存文章列表、文章内容、图片 URL 映射,这样同一篇文章不用重复处理。
整个流程下来:
- 我在 Obsidian 按 Ctrl+S
- 1 秒后 Git 插件推送到 Gitee
- 2 秒时 Gitee 发 Webhook 给 Vercel
- 接下来 Vercel 花几秒处理(验证签名、拉取文件、解析 Markdown、处理图片如果有新图片、写入 Redis、触发 ISR 重新生成)
- 到第 8 秒用户刷新页面就能看到新内容了

平均 8 秒,从保存到全世界可见。
如果有缓存命中,可以快到 2-3 秒。
很多人会问为什么不用 GitHub Actions。
那个太慢了,启动容器 30 秒,安装依赖 1 分钟,构建整个站点 3-5 分钟,部署 30 秒,加起来至少 5 分钟。而且每次都要重新构建整个站点,哪怕你只改了一篇文章。
用 Webhook + ISR,只处理变化的部分,快多了。
成本的话,这套方案基本是免费的。
Vercel 免费额度够用(100GB 带宽/月),Gitee 免费,DogeCloud 有免费额度超了也很便宜,Redis 用的 Upstash。
完结撒花
我知道会有人说这个方案太复杂了。
它确实很复杂,但我就是喜欢这么搞,每一个都优化到尽量极致。em也算是我的奇思妙想吧)
我的博客在Github进行了开源
包括所有完整代码。你可以直接获得~