· 阅读约 1 分钟
这个站是怎么搭的
这是站点的第一篇文章,同时也是排版样张。确认样式没问题之后可以直接删掉它——
删掉 content/posts/how-this-site-works.md,重新构建就没了。
为什么不用 Hexo 或 Hugo
作品集页面是手写的 HTML,栅格和留白都是按视觉稿一像素一像素调出来的。 套进任何一个博客框架,都要先把它拆成框架的模板语法,再和主题的默认样式打架。
所以这里反过来:框架只负责文章,不碰已经写好的页面。
整个构建就是一个 build.mjs,两百来行,做四件事:
- 读
content/posts/*.md,解析 frontmatter; - 渲染成
public/writing/<slug>/index.html; - 生成
feed.xml、sitemap.xml、robots.txt; - 把首页里
<!-- build:recent -->标记区间的内容换成最新三篇。
手写的 index.html 和 project.html 除了那几个标记区间,一个字节都不会被动。
写一篇文章
在 content/posts/ 下新建一个 .md,文件名就是 URL:
# content/posts/scaling-inference.md → /writing/scaling-inference/
npm run dev # 起监听,改完存盘自动重建
frontmatter 只有 title 和 date 是必填的:
---
title: 推理服务的三次重写
date: 2026-09-12
summary: 从单机脚本到多租户网关,每一次重写解决的都是上一次没想清楚的问题。
tags: [机器学习, 系统设计]
draft: true
---
draft: true 的文章不会被构建。想在本地预览草稿:
npm run build -- --drafts
数据在自己手里
| 能力 | 方案 | 部署位置 |
|---|---|---|
| 访问统计 | Umami | 同域 /_a,绕开广告拦截 |
| 评论 | Waline | comment.wenjunjia.cloud |
| 静态托管 | Caddy | systemd,自动续期证书 |
统计不写 Cookie,也不做跨站追踪,所以不需要弹隐私横幅。 评论支持匿名,邮箱选填,只在有人回复时用来发通知。
用第三方服务省下来的时间,迟早会以数据被拿走、或者服务下线的形式还回去。 一台八块钱一个月的机器能解决的事情,不值得让渡数据。
代码块长这样
def reading_minutes(text: str) -> int:
"""中文按字、西文按词分别估算。"""
cjk = sum(1 for ch in text if "一" <= ch <= "鿿")
words = len(text.encode("ascii", "ignore").split())
return max(1, round(cjk / 400 + words / 220))
行内代码是 --rootMargin: 400px 这种样子,链接是
Caddy 的文档 这种样子。
有问题直接在下面留言。
评论