☰
告别数据库:caveman极简静态博客引擎从入门到部署
2026/10/14 7:51:10 网站建设 项目流程

在技术圈混久了,你会遇到一些名字起得特别不正经、但内核特别认真的项目,caveman就是其中之一。我第一次看到这个词,脑子里浮现的是披着兽皮、举着石斧的原始人,心想这大概又是哪个程序员喝多了之后的玩笑作品。直到我顺着项目源码翻下去,才发现它是 Instagram 创始人 Kevin Systrom 写给自己用的极简博客引擎——文章用 JSON 存,模板用 ERB 写,构建靠 Rake 任务,最终吐出一堆纯静态 HTML,扔到任意静态托管上就能跑。

这个"穴居人"式的方案,恰恰解决了我很长一段时间里最烦的问题:博客系统太重,后台太多,写作本身反而变成了一件需要心理建设的事。

如果你也和我一样,受够了动态博客的数据库备份、插件升级、后台维护,又恰好想要一个完全掌控、打开浏览器就飞快的内容站点,那这篇东西应该能帮你省下不少摸索时间。我会从这项目到底解决什么问题讲起,再到一步步跑通、踩坑、部署,最后聊点真实使用下来的体感——保证不是那种"照着 README 念一遍"的凑数文章。

1. 先搞清楚 caveman 是什么,以及它到底替你解决了什么

一个项目能用一个有自嘲意味的名字,通常说明作者对行业现状有点意见。caveman这个名字的潜台词就是:现代博客系统把简单的事情搞复杂了,我要退回石器时代,用最笨、最直白的方式解决"我想发一篇内容"这件事。

1.1 一个怪名字背后,是对重型博客系统的反叛

先交代下背景。Kevin Systrom 在 Instagram 被收购后,有段时间自己写博客,但他不想用 WordPress,也不想去折腾数据库。于是他写了一个非常原始的工具:文章以 JSON 文件形式放在目录里,模板用 Ruby 的 ERB,本地执行构建命令,输出静态 HTML。整个项目从一个非程序员的角度看,几乎没有任何"花哨"的地方。

但这个工具的思路很快吸引了一批"内容为王、技术为辅"的独立创作者。你看它的设计语言就很直白:没有后台管理界面,没有数据库连接,没有插件市场,没有权限系统。你要发一篇文章,就新建一个 JSON 文件,写标题、日期、正文,然后构建。

这套流程对我们这种"写作和技术都想要"的人来说,反而是一种减负。因为博客的本质是内容管理,而内容管理的核心矛盾从来不是功能不够,而是每次想写点东西之前,得先和系统本身搏斗一番。

1.2 告别数据库:文章就是文件,文件就是文章

传统博客最让人难受的一点是,你的内容是锁在数据库里的。备份要导出 SQL,迁移要匹配版本,改个字段结构要小心翼翼。而在caveman这类静态方案里,"内容即文件",一个 JSON 文件就是一篇完整的文章、一个页面。

这个转变听起来小,实际体感差异巨大:

  • 备份从"导出数据库"变成了"整个目录都已经在 Git 里"
  • 迁移从"找工具、倒数据、修编码"变成了"把文件夹拷过去"
  • 历史版本从"靠插件审计"变成了"git log直接看"

我自己这些年折腾过各种独立站点,最后发现,越是高级的方案,后续维护的隐形成本越高。数据库本身没毛病,但为了维护数据库而配套的升级、备份、安全补丁,才是真正吃掉你时间的地方。caveman直接从根上把数据库砍掉了,你甚至不需要知道数据库存在过。

1.3 静态博客与动态博客的取舍账

很多人一听"无数据库",第一反应是"那是不是功能很弱"。这话对也不对。弱的是那些需要数据库才能做的功能,比如用户注册、评论交互、实时统计;但如果你要的只是"发文章、排期、展现内容",静态方案不仅不弱,反而在速度和稳定性上吊打动态方案。

我整理过一个比较直白的对比表,发出来供参考:

对比维度动态博客(数据库+后台)caveman 这类静态方案
打开速度依赖服务端渲染和缓存纯静态文件,CDN 直接命中
安全风险登录后台、插件、数据库注入都要防没有后台、没有数据库,攻击面极小
备份恢复需要导出数据库并验证完整性整个站点就是 Git 仓库
写作摩擦先登录后台,再处理编辑器本地写 JSON,命令行构建
功能扩展靠插件,但插件会互相冲突自己写模板和脚本,可控但朴素

所以这个项目名字叫caveman,本质上是在提醒你:有些现代工具给你的"便利",其实是把你拖进一个永远收拾不完的复杂度泥潭。而回到穴居人的状态,你反而能获得最纯粹的东西——一个打开就跑、不会半夜崩溃的网站。

2. 为什么选"穴居人"方案:一次理性的选型分析

如果你只是想要一个能发布东西的网站,选择其实很多。有托管在云上的 SaaS 平台,有开箱即用的静态站点生成器,也有caveman这种极其"个人向"的工具。那我为什么最终选它?不是因为名字好玩,而是它踩中了我对内容发布的几个核心诉求。

2.1 把文章和站点当作一套完整的代码库

我最喜欢caveman的一点,是它把"写博客"和"写代码"完全 merged 到了一起,你不需要学习两套心智模型。

发一篇新文章,我的操作路径是这样的:

  1. 在content/articles/目录下新建一个 JSON 文件
  2. 写好标题、日期、分类、正文内容
  3. 本地跑构建,确认渲染效果
  4. git commit和git push,远端自动构建发布

在这个流程里,文章是带正规历史记录的代码,页面改动是 Commit,换主题是重构。如果某篇文章写错了,想回滚到旧版,你不需要去后台翻什么"修订历史",直接在 Git 里切回去就行。

这种体验,是你在 WordPress 上无论如何都找不到的。WordPress 当然也能通过插件做修订,但一旦你接受了"内容即代码"这个设定,再看那些后台草稿箱、自动保存、旧版本清理机制,就会觉得特别冗余。

2.2 省掉的是维护心智,多出来的是写作时间

很多人忽略了一个成本:技术债不是写在代码里的,而是写在你每天的心理负担里的。动态博客每天都会在后台多出几个"有安全更新可用"的提示,插件三个月不更新就开始心虚,数据库日志偶尔冒出几行报错——每一个小问题单看都不大,但累积起来,你会潜意识地把"维护博客"当成一件需要定期去做的事。

caveman这种方案把维护成本几乎压到了零:没有后台,没有插件,没有数据库。你唯一需要维护的是 Ruby 环境和几条 rake 命令,而这些在写博客的人手里,基本可以忽略不计。

我实际用下来,最明显的感受是:打开电脑想写点什么的时候,直接开编辑器就能开始,不用先登录后台、等编辑器加载、切一堆设置。写作的摩擦感小了,产出频率自然跟着上来。

2.3 极简方案也有明确的边界,不适合的人别硬上

当然,这不是一个"万金油"方案。caveman适合的场景是个人内容发布:技术博客、生活记录、极简文档站、个人作品集。它天生不适合:

  • 需要大量用户交互的社区站点
  • 需要用户注册、评论、会员体系的业务系统
  • 以实时数据展示为核心的仪表盘型网站
  • 运营人员不会写代码、需要可视化编辑的协作场景

如果硬要在这些场景里用纯静态方案,你会发现自己需要造的轮子比省下来的还多。我能理解开源社区里那句调侃:caveman是给"一个人 + 一个编辑器 + 一台服务器"的场景设计的,一旦人数超过三个,就要慎重。

所以我的建议是,先问自己:我的站点是"内容中心"还是"业务中心"?前者用caveman恰到好处,后者还是老实去找合适的重量级方案。

3. 从零跑通一个 caveman 站点:完整实操过程

理论讲完了,该动手了。这一节我会尽量按我第一次跑通这个项目时的完整过程来写,每一步都包含具体命令和文件内容,你照着做就能在本地跑出一个能看的站点。

3.1 环境准备:Ruby 和 Bundler

caveman是 Ruby 写的,所以第一步是确保本地有 Ruby 环境。我的机器上用的是 Ruby 3.x,配合bundler管理依赖。

# 检查 Ruby 是否存在 ruby -v # 安装 bundler(如果还没有) gem install bundler

如果 Ruby 版本太老,建议你先升级环境,否则后面装依赖时可能会遇到兼容性问题。我遇到过最典型的问题就是项目里依赖的sinatra和sass在旧版 Ruby 上编译报错,升级环境后一遍过。

接着把项目克隆下来:

git clone <caveman 仓库地址> caveman-demo cd caveman-demo # 安装项目依赖 bundle install

这一步会下载sinatra、rack、sass、json等 Gem。装完以后,项目的骨架就齐全了。

3.2 理解核心目录结构

caveman的目录设计非常克制,核心就几个文件夹。我用自己的项目打个样:

caveman-demo/ ├── config.json # 站点全局配置 ├── content/ │ ├── articles/ # 所有文章,一篇一个 JSON │ └── pages/ # 独立页面(如关于页) ├── templates/ │ ├── layout.erb # 整站布局模板 │ ├── article.erb # 文章页模板 │ └── index.erb # 首页列表模板 ├── public/ # 构建输出的静态文件 ├── Sass/ # 样式源文件 └── Rakefile # 构建任务

这个结构基本上十分钟就能看懂。config.json存放站点名称、描述、作者信息等全局内容;写内容时只用关心content/目录;构建后输出的文件全会进public/。就算你从没写过 Ruby,只要会看 JSON 和基本 HTML,维护起来也不吃力。

3.3 写出第一篇文章:一个 JSON 文件而已

caveman把内容存储在 JSON 文件里,一篇文章对应一个文件。我假设你已经建好了content/articles/目录,在里面新建一个文件,名字建议带日期和标题,比如20250120_hello-caveman.json。

{ "title": "Hello Caveman", "date": "2025-01-20", "tags": ["hello", "blog"], "body": "写文章的过程,其实可以简单到只是一个文件、一个命令。" }

字段含义很直白:title是标题,date是发布日期,tags是标签,body是正文。有的版本还支持excerpt用于首页摘要,我没写也不影响构建。这里有个值得注意的细节我后面会单独说:date字段的格式非常关键,稍不标准就会导致文章排序错乱。

正文从body字段进去,换行处理取决于模板怎么渲染。我自己的项目里会用 Markdown 格式写正文,再在构建时转换成 HTML,这样既能享受 Markdown 的写作体验,又能保持文件纯粹是纯文本。

3.4 本地预览:一条命令搞定

跑通本地预览,依赖Rakefile里定义的任务。不同版本的caveman任务名可能略有差异,我用的版本里,开发预览和正式构建是这样触发的:

# 本地开发预览,通常会自动起一个端口 rake dev # 正式构建,输出静态文件到 public/ rake build

先跑rake dev,终端会打印出一个本地地址,一般是http://localhost:4567(Sinatra 默认端口)。浏览器打开,就能看到首页列表和文章页了。

如果你用的是 Docker 或远程开发环境,记得把端口映射出来,不然会像我第一次一样卡在"明明服务起了,但浏览器就是打不开"的尴尬里。

3.5 首页排序和文章渲染的初步结果

跑起来以后,你会看到首页上列出了所有文章,按日期排序。这个排序逻辑是caveman自己实现的,它会读取文章的date字段,然后按时间倒序排。所以只要你写文章时date规范,首页基本不会再乱。

点击一篇文章,会进入文章页,渲染的就是templates/article.erb模板。默认模板极其朴素,标题、日期、正文三段式。如果你想加点赞、分页、上一篇下一篇之类的功能,就得自己写了——这正好说明了这个项目的定位,它把内容展示的事做到最简单,复杂需求全部交给使用者。

4. 实际使用中容易踩的坑:完整排查链路

任何极简工具,配套文档也会"极简",很多问题不说清楚,全靠你试错。下面这几个坑是我实际踩过、也帮别人排查过的,有的坑如果你不看这篇文章,可能会被卡上一整天。

4.1 手写 JSON 的格式纪律:一次排序错乱的排查

刚用caveman时,我一口气写了五篇文章,构建完发现首页顺序完全不对,新发的文章排在最后面。第一反应是源码有 bug,但仔细想想不太可能,作者自己常用这个工具,排序功能不至于坏。

我开始从头排查。第一步,先确认首页模板在用什么字段排序——它遍历的是 Articles 集合,按article.date倒序。第二步,手动检查那几篇文章的 JSON 文件,发现其中一篇的日期写成了2025/01/03,另外几篇是2025-01-05、2025-01-06这类标准格式。

问题就出在这里。程序做日期比较时,拿到的是字符串,字符串比较是一个字符一个字符进行的。2025/01/03这个字符串,在第三个字符位置就变成了斜杠/,而其他字符串第三个字符是短横线-;ASCII 里/的编码比-大,所以在倒序排列时,这篇日期实际看起来比 2026 年还要"大",被排到了最前面。

这个坑的核心教训是:一定不要以为 JSON 里的日期可以随便写。即使字段名叫date,很多工具也不会自动解析成时间对象,而是当成字符串比较。统一用YYYY-MM-DD这种 ISO 8601 格式,就不会出现这种问题。

顺带提一句,编码格式也要注意。JSON 文件必须统一保存为 UTF-8,否则中文正文在构建出来之后可能会变成乱码。我遇到过有人用 Windows 自带记事本保存文件,默认带 BOM,Ruby 解析 JSON 直接报错的例子。

4.2 模板层别自作聪明:保持逻辑最小化

caveman的模板是 ERB,说白了就是 HTML 里嵌 Ruby 代码。因为这套模板足够自由,很多人会忍不住在里面写各种条件判断、循环嵌套、数据变换。

我有个真实的教训:为了做"文章详情页底部展示相关文章",我在article.erb里写了一段循环,遍历所有文章,取相同标签的列出来。从功能上看没问题,但当文章数量超过一百篇以后,每次打开文章页都要全量遍历一次,构建时间肉眼可见地变长。更头疼的是,那一段内联逻辑分散了模板的注意力,后面想改页面布局时,稍微动一下结构,逻辑就跟着乱。

caveman这种单体模板工具,适合的是"布局清晰、逻辑最少"的思路。需要在页面显示的数据,尽量在构建前处理好,模板里只做展示,不要做计算。如果非要写一点辅助逻辑,也应该抽到独立的 Helper 方法里,而不是塞在模板中间。优秀的模板应该是你一眼看过去就能知道页面结构,而不是像一碗没拌开的芝麻酱。

4.3 静态资源路径问题:部署到子目录的翻车现场

caveman构建出来的页面,默认使用的资源引用路径可能和你部署的实际路径对不上。public/目录里的 CSS、JS,模板里如果写的是绝对根路径/css/style.css,本地跑没问题,因为你站点就是部署在域名根路径下。但如果你要放到https://example.com/blog/这种子目录下,所有资源请求都会跑到https://example.com/css/style.css去,直接 404。

我的处理方案是在模板里统一使用相对路径,或者在config.json里配置一个统一的站点基础路径变量,所有资源引用都基于这个变量拼接:

<link rel="stylesheet" href="<%= config.base_url %>/css/style.css">

这样当我把站点从根路径迁到子目录,只需要改一个配置项。这个问题刚出现时没有任何报错,页面上只显示样式全丢、布局错乱,很容易让人怀疑是 CSS 文件写坏了,实际还是路径没对齐。

4.4 构建任务重复执行的旧文件残留

另一个我踩过的坑是:删除一篇文章后重新构建,线上竟然还能访问到老页面。排查过程比较绕,先说结论——rake build只负责把当前内容渲染生成新文件,并不会先清空public/目录。也就是说,如果你之前构建出过deleted-article.html,之后把文章 JSON 删了,再构建,这个 HTML 文件仍然安静地躺在public/里。

浏览器直接访问老页面,因为静态文件还在,照样能打开。这不是caveman独有的问题,所有"增量生成 + 静态输出"的工具都存在。解决办法是在构建之前,先把输出目录整个清空:

# 先清空,再构建,保证线上文件始终和当前 content 完全一致 rm -rf public/* rake build

我建议直接把这个清理命令写进部署脚本里,让它成为流程的固定动作。否则某次你兴致勃勃改了一堆内容,自认为已经把旧文章"删干净"了,结果读者通过搜索引擎访问旧链接,点进去还是满血状态,就很尴尬。

5. 部署上线与真实使用感受

本地构建跑通,剩下的就是把public/目录发布到公网。这部分的方案很成熟,你甚至不需要买一台服务器,用对象存储或者任意静态托管服务都行。

5.1 最简部署:用 Nginx 托管静态文件

我自己是放在一台 Nginx 服务器上。流程很简单:把public/目录里的内容传到服务器的站点目录,然后配置一个 server block:

server { listen 80; server_name example.com; root /var/www/caveman/public; index index.html; location / { try_files $uri $uri/ =404; } }

caveman是纯静态输出,Nginx 只需把文件路径对应到 URI。因为没有任何服务端计算,请求压力也非常小,即使暂时不配 CDN,直接用 Nginx 也能扛住不小流量。

如果你用的是 Cloudflare Pages、Netlify、GitHub Pages 之类的托管服务,操作更简单:把public/作为发布目录,链接到 Git 仓库,推送即部署。这个方案的额外好处是自动支持 HTTPS,省掉证书续期的麻烦。

5.2 发布流程自动化:Commit 之前顺手构建

纯静态流程最大的优势是适合自动化。我把发布流程写成了一个脚本,每次更新只做一件事——推代码。

核心脚本思路是这样:

#!/usr/bin/env bash set -e rm -rf public/* rake build # 推送到远程服务器 rsync -avz --delete public/ user@server:/var/www/caveman/public/

rsync --delete参数会自动把源端没有的文件从目标端删掉,正好解决了上节说的旧文件残留问题。你可以把这个脚本接到 Git pre-push hook 里,实现"写完文章、git push、站点自动更新"的效果。

用久了之后,发布这个动作会变得极其轻量。传统动态博客"登录后台 → 写文章 → 点发布"的过程,在caveman里被压缩成"写 JSON → 构建 → 推送",全程不会离开命令行环境。

5.3 实际用了一周之后的真实体感

到这一步,我不得不谈点"感受化"的东西了。因为博客这东西,最终只有你在频繁使用,才知道螺丝拧得合不合手。

先说舒服的地方。写作环境完全可控,我直接在自己熟悉的编辑器里写,语法高亮、补全、快捷键全部保留。写作质量和工具迁移成本之间没有任何纠缠,今天用记事本写,明天换成 Vim,后天改用 VS Code,都无所谓,因为内容就是 JSON 文件。另一个我很喜欢的地方是改版成本极低。我想调一下首页布局,改一个index.erb,重新构建,整站样式就统一变了。没有主题升级、没有兼容性测试、没有"改了一处然后插件不兼容"的连锁反应。

再说不舒服的地方。评论和互动功能得自己另想办法。我目前采用的是把评论引导到邮件和社交平台,等于完全没有站内评论。如果你的文章经常引发讨论,你可能会觉得少了点什么。还有就是可视化不方便,你在本地写 JSON 的时候,看不到图文混排的效果,必须构建之后打开页面才知道排版是否理想。对我这种不依赖复杂排版的人无所谓,但对喜欢在文章里插大量图片的人,就会觉得每一步都在"盲写"。

还有一个需要适应的习惯是预览反馈的循环。虽然rake dev可以本地实时预览,但你写完一段话,总归要切到浏览器刷新一下,而不是像后台编辑器那样实时看到渲染结果。这个摩擦在长文写作时尤其明显,需要你自己调整节奏。

但综合来看,我用完一周的感受是:caveman这类的极简方案,真正的价值不是功能上的胜利,而是它把"发一篇内容"这件事的技术成本降到了足够低,低到你会更愿意坐下来写作。这比任何花哨的后台功能都更接近博客的本质。

如果你现在手上正好有一个"拖了很久没开始做"的博客计划,我建议你拿一个周末的时间,照着这个思路搭一个试试。不用担心它太简陋,先跑起来,写点东西,然后你会发现,真正重要的并不是平台或工具有多先进,而是你终于把注意力放回了内容本身——这大概就是"穴居人"要告诉你的道理。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询