这里是简历中提到的项目的相关资料与照片。简历上的二维码指向本页,扫码即可查看细节。
这里是简历中提到的项目的相关资料与照片。简历上的二维码指向本页,扫码即可查看细节。
这个周末有空就搞了一下前端,开发的设备因为一些原因用不了了。代码已经推到 GitHub 上,在新电脑上 clone 下来就能继续。
但事情没有想象中那么顺利。
新电脑上什么都没有。没有 Python,没有 Node.js,没有字体,没有编辑器。从头来。
博客已经在前一台设备上迁到了 Astro,所以这次只需要装 Node.js 就够了。但 Windows 上装 Node.js 也出了一点状况——winget 不可用,直接下载安装包需要管理员权限兜兜转转最后用了一个之前解压到一半的 v22.12.0。把路径写到系统环境变量里,重启终端,终于认了。
node --version # v22.12.0
npm --version # 10.9.0
npm install 一把过。
第一篇文章里提到过,最初的博客是纯 Python 方案——每个 Markdown 文件手动转成一段 HTML,然后用字符串模板拼进 base.html 里。简单高效,但谈不上什么设计感,MacOS 风格的模糊导航栏加上麦当劳配色(红色导航栏配白色背景),能用就行。
这次迁移到 Astro,不只是换了个构建工具。借着重新拆解组件的机会,也重新设计了整个视觉。
键盘圈有一个经典的复古配色叫 GMK 9009,cream + cement + orange,暖灰调里带一点橙色点缀,像是从八十年代的工业设计手册里撕下来的。我之前折腾机械键盘的时候就对这个配色印象很深。
把它搬到了博客上:
:root {
--cream: #F5F3EE; /* 页面底色,乳白偏灰 */
--cement: #C4C9C9; /* 边框、分割线、侧边栏标题 */
--orange: #F46822; /* 链接、高亮、hover */
/* ... */
}
不是纯白背景戳眼睛,不是纯黑看久了压抑。比第一版的麦当劳配色安静很多,也更耐看。
字体选了 JetBrains Mono——程序员最喜欢的等宽字体之一,以前用 Monaco,这次换过来。字型大了一圈,行宽也放宽了,每行大概 80 个字符左右。
原来的 base.html 是一整坨 200 行的大模板,Header、侧边栏、搜索框、Footer 全部揉在一起,改任何东西都得扫一遍全文。
拆成 Astro 组件之后:
Base.astro:页面骨架,包含 Header、侧边栏、Footer,通过 <slot /> 插入页面内容index.astro:首页,遍历文章列表生成摘要[slug].astro:文章详情页,Markdown 渲染 + KaTeX 数学公式侧边栏是整站变化最大的地方。之前只有一个链接列表,现在加上了 About 简介、全部文章归档、以及 Elsewhere 外部链接。每次都手动从文章列表里更新最近文章,虽然麻烦,但相比之前的那种”孤零零的页面”,已经有了点”博客”的样子。
跑 npm run build,报错。
第一篇文章里有一张天空的照片。在旧的 Python 方案里,图片放在项目根目录的 images/ 下,文章里用 images\xxx.jpg 引用。Markdown 解析器不关心斜杠方向,直接拼路径就行。
Astro 不一样。它用 Vite 处理资源,图片需要用正斜杠,而且路径是相对于页面根的。更关键的是——图片得放在 public/ 目录下。这是 Astro 的约定:public/ 下的文件原样输出,不经过 Vite 的处理管线。
修改:
- 
+ 
顺便把图片挪到 public/images/。
搜索功能是纯前端方案:构建时生成 search.json,一段 JS 做即时检索。旧的代码里搜索结果链接写死了 .html 后缀:
'<a href="' + p.slug + '.html" class="search-result-item">'
但 Astro 默认生成的是 Clean URL(/posts/slug/ 不带 .html),所以搜索结果点进去全是 404。
改成:
'<a href="/posts/' + p.slug + '/" class="search-result-item">'
astro build 不报错,但打开页面是一个毛坯房——所有的样式都没了。检查一下生成的 HTML,<head> 里只有一个 Google Fonts 的 <link>,没有任何 CSS。
原因在 Base.astro 里:
import '../styles/global.css';
这段代码看起来没问题——在 Astro 的文档里这也是推荐写法。但不知为什么,Vite 在处理的时候没有把它打包进去。dist/_astro/ 下只有 KaTeX 的字体文件,没有任何 CSS 文件。
排查了一圈,最简单的解决方案是把 CSS 放到 public/ 下让它原样输出,然后在 <head> 里用传统方式 link:
- import '../styles/global.css';
+ <!-- 移到 public/styles/ -->
<link rel="stylesheet" href="/styles/global.css">
CSS 文件本身不用改,一个字都不动。
旧的 Python 时代遗留下一些文件——posts/ 目录(文章已经移到 src/content/posts/ 里了)、多余的 images/ 目录。这些都删干净了。README 也更新成 Astro 的说明。
| Python 方案 | Astro | |
|---|---|---|
| 本地预览 | python dev.py | npm run dev |
| 构建 | python build.py | npm run build |
| 热更新 | 文件变化触发完整 rebuild | HMR,只刷新变化的部分 |
| 文章存放 | posts/*.md | src/content/posts/*.md |
| 图片 | images/ | public/images/ |
| 布局 | Python 模板字符串 | Astro 组件 |
| 数学公式 | MathJax(按需加载) | KaTeX(构建时渲染) |
| 搜索 | 纯前端 JSON + JS | 同上,基本没变 |
| 配色 | 麦当劳红白 | GMK 9009 Cream + Cement + Orange |
| 排版 | Monaco,窄行宽 | JetBrains Mono,放宽行宽 |
Astro 带来的最大改进是组件化。侧边栏、文章列表、页面头尾——每个都是独立的组件,改一个地方全站生效。之前改一下 CSS 要手动 rebuild 所有页面,现在保存就立即看到结果。
这次迁移暴露了一个问题:import CSS 在 Astro 里时灵时不灵。可能跟具体版本有关,也可能是路径解析的问题。目前用 <link> 的 workaround 能用,但之后想搞清楚为什么——也许能变成一篇 debug 笔记。
还有就是这个新的搜索又卡又不管用,回头有时间再来修修补补吧。
现在发现这个搜索并不是不好用哦是我的 github page 没选择 Github Action 自动部署,而是选择了手动部署,所以每次修改后需要手动部署才能看到效果。
我一直想有一个自己的博客。不是那种用现成主题、五分钟搭好的博客,而是一个每一行 CSS 我都知道为什么这么写的博客。
Simon Willison 的博客是我一直以来的参考。内容即界面,没有多余的东西——没有侧边栏小部件、没有社交分享按钮、没有评论区。打开页面,只有文章。
我想做类似的东西,但有几个自己的偏好:
最开始尝试了 Jekyll。本地跑不起来,每次改 CSS 都要靠想象,改完 push 上去等 GitHub Pages 构建才知道效果——这个反馈循环太慢了。
后来改成了纯 HTML。所有的 .md 文件用 Python 脚本转换成 HTML,本地 python dev.py 启动一个服务器,保存文件后浏览器自动刷新。零构建时间。
几个关键的库:
markdown # Markdown -> HTML
Pygments # 代码语法高亮
python-frontmatter # 解析文章元数据
加起来不到 100 行的 build.py,做了三件事:
posts/*.md,解析 frontmatter(标题、日期、类型)搜索用的是纯前端方案:构建时生成 search.json,页面上一段 50 行的 JS 做即时检索。不需要任何后端。
我不总是写长文章。很多时候只是记录一下今天做了什么,或者分享一篇读到的好东西。所以设计了三种内容类型:
| 类型 | 用途 | 例子 |
|---|---|---|
| Article | 正式长文 | 就是这篇 |
| Note | 每日小结 | 今天修了三个 bug,学了两章 Rust |
| Link | 资源分享 | 推荐文章 + 简短评论 |
首页会展示所有类型的全文,按时间倒序排列。长文章底部有一个 Permalink 链接。
配色是在路过麦当劳的时候定下来的。麦当劳门店那种红、金、暖灰的组合意外地好看。
#DA291C(麦当劳红)——侧边栏、链接、按钮#FFC72C——代码块左边框#E5E1DC——页面背景#2D2D2D 深色,和灰色背景拉开层次整个过程是聊出来的——我描述想法,Claude 帮我写代码。CSS 调了五六版才到现在的状态,中间踩了不少坑:
文章里可以写 LaTeX 数学公式,用 MathJax 渲染。行内公式比如 可以直接写在段落里,块级公式也支持:
只在包含公式的页面才加载 MathJax,不浪费带宽。
整个博客是一堆静态 HTML 文件,托管在 GitHub Pages 上。更新流程:
python new.py # 新建文章
# 编辑 posts/xxx.md
python build.py # 构建
git add . && git commit -m "新文章"
git push # 上线
从写完到上线不超过一分钟。
纯 Python 的方案用了一阵子之后,还是发现了一些痛点:
于是把博客整个迁移到了 Astro。迁移过程比想象中顺利,因为之前的 HTML 模板结构已经很清晰:
Base.astro 做布局,index.astro 做首页)src/content/posts/现在的工作流:
npm run dev # 本地预览,热更新
# 编辑 src/content/posts/xxx.md
npm run build # 构建
git push # 上线
Astro 默认输出零 JS,和之前纯静态 HTML 的性能一样好。但开发体验好了很多——组件化让修改布局变得简单,热更新让写 CSS 快了几个数量级。
这个博客会持续演进。目前想加的东西:
但大概率不会加评论系统。保持简单本身就是一种功能。
