零脚本静态博客的工程实现:这座博客是怎么造出来的
构建八秒、发布一条命令、全站零 JavaScript。这篇拆解这座博客自身的工程:选型、发布链、验收体系,和三个真实的设计决定。
你现在读的这座博客,是一个适合自我解剖的对象:它的全部工程都在今天的记录里。这篇把三层拆开——选型、发布链、验收——并讲清楚三个关键设计决定的来龙去脉。
选型:一个决定,两个备选
框架层面的决定前面有文章写过:静态优先,零脚本默认,交互按需采购。真正想补充的是工程视角的对比。静态组里最终入围的是 Hugo 和 Astro:前者是单二进制的极简主义,构建最快、依赖最少;后者是组件化的现代工程,内容集合带类型校验,今年的新版本把编译链重写为 Rust 后构建速度也追了上来。
最终选 Astro 的决定性理由只有一条:交互组件的宿主。规划中这个站未来要往文章里嵌工程计算器,岛屿架构让交互组件可以按需局部加载而页面其余部分保持纯静态——这件事在 Hugo 里要手写脚本挂载,工程上别扭得多。选型不需要选“最好的”,要选“和你的下一步最合拍的”。
发布链:一条命令的背后
发布链的设计目标:写作的人只管写,发布的全部复杂度收进一条命令。现状是:构建(约八秒)→ 打包 → 经加密通道上传(校验和比对,防止静默截空)→ 远端原子替换 → 源码提交推送 → 线上验收回显。任何一步失败,链条即停。
三个工程细节值得展开。传输通道:这台目标服务器的文件传输子系统是坏的,所有上传走“编码流经命令通道+远端解码+哈希校验”的方案——通道不可靠时,校验和就是生命线。原子性:远端先清空再解压的窗口期以秒计,新站无人在线时可以接受;正经站点应改为“解压到新目录+原子切换”。配置纪律:站点的服务端配置有三条铁律——全站禁用某协议版本(它弄死过长连接)、绝不加“禁止收录”标记(这是收录站,和内网工具站策略相反)、带哈希的静态资产用不阻断安全头继承的缓存指令——每一条背后都是一次真实事故。
验收:不信任任何“应该”
这座站的验收体系可能是最超规格的部分,因为它继承了主站被教育过的所有教训。
几何断言:移动端适配不用截图目检,用设备仿真实测页面滚动宽度是否等于视口宽度——因为老式截图方式会产出“伪溢出”的幻觉截图,我们差点据此把正常页面改坏。一个验收脚本,传入地址和宽度,退出码即判定。
四档视口:三百二、三百九、七百六十八、一千四百四,四档全部断言加截图目检。桌面看了没问题不代表手机没问题,反过来也一样。
内容反查:发布前扫全部文章——敏感信息(IP、端口、凭据)用模式匹配,中英混杂的乱码用正则抓,单篇字数做分布统计。这个流程抓出过三处混入正文的英文残词和一次几乎漏出去的细节。
线上终验:本地通过不算数,发布后线上逐条路由回状态码、内容抽查、计数对账。有趣的是,连验收本身都翻过车——单行 HTML 让按行计数的检查报了零,换成内容级匹配才抓到真相。验收工具也是代码,也要被验收。
写作流:没有后台的取舍
零后台是特点也是代价:写作是改文件、提交、发布,手机上随手改稿、多人协作这类能力天然缺失。我们接受这个代价的理由:这是一个人的博客,写作发生在桌面端,版本管理比可视化后台更符合工程习惯。缺的能力各有补偿方案备用:要网页后台,有基于 git 的轻量内容管理面板可加;要手机投稿,走邮件草稿再入库。但都停留在“备而未装”——每个补偿方案都有自己的维护成本,没有真实需求之前不装,这是零脚本原则在工具链上的延伸。
成本账
工程的每一步都有账,列出来供同类项目对标:构建时间八秒(四十多页);产物体积连图不到两百 KB,压缩包几十 KB;传输经编码流通道,秒级;发布全链(构建到线上验收)一分钟内;运行内存为零(纯静态文件);源站攻击面为零(无后端可打)。对比曾经运营过的动态站——缓存层、数据库、程序升级、安全补丁——静态方案的维护成本接近于零,这也是它敢把“活得久”写进目标的原因。
后续演进路线
当前的发布是手动一条命令,下一步可演进为推送即自动发布:代码托管平台的事件驱动构建, push 完线上自动更新——脚本与验证体系都已就位,只差把触发器接上。评论与搜索按需上:评论用独立的第三方容器(不进静态产物),搜索用构建期生成的静态索引——两者都保持“交互是采购的,页面是纯静态”的架构原则。更远一步,是把工程计算器以岛屿组件的方式嵌进相关词条文章:交互局部加载,页面其余部分依旧是零脚本——这条路线在设计选型时就已铺好。
结语
有读者可能觉得,一个个人博客不值得这套工程。我的看法相反:正因为个人博客的读者少,每一次访问都是全部;也正因为没有团队兜底,每一环都必须自动且可验证。工程的美感不在规模,在每一层都知道自己为什么存在。