1446 字
7 分钟
阅读量:7 次

这个博客是怎么搭起来的:Astro + Fuwari 的四个真实坑

🤖AI 摘要
AI

这个博客是我自己搭的,从选型到踩坑前后折腾了不少时间。常有朋友问用的什么方案,这篇就一次说清楚:技术栈是什么、为什么这么选、以及几个真把人卡住的坑。用的技术都挺主流,坑却都很具体,如果你也打算用 Astro 搭个人站,这篇大概能帮你省掉一两个下午。

技术选型#

部分用了什么
站点生成Astro 5(纯静态输出)
交互组件Svelte 5
样式Tailwind 3 + Stylus
站内跳转@swup/astro(无刷新导航)
全文搜索Pagefind(构建后生成索引)
部署GitHub Actions → rsync → 自己的 VPS + nginx

选静态生成的原因很简单:博客内容几乎不变,不需要服务端。构建出一堆 HTML 直接丢给 nginx,没有数据库、没有运行时,安全面和维护成本都降到最低。代价是评论、访问统计这些必须依赖第三方服务,这一点后面会提到。

主题基于开源的 Fuwari 二次开发,但下面这些坑大多不是主题特有的,而是 Astro 这套体系本身的特性。

坑一:文章标题就是 URL#

本站的文章地址长这样:

https://www.daitcc.top/posts/4584a3ea/

后面那 8 位十六进制不是随机数,而是 sha1(文章标题) 的前 8 位。

后果很直接:改一次标题,这篇文章的 URL 就变了。旧链接立即 404,搜索引擎已经收录的地址也会失效,如果之前分享过给别人,那些链接全部作废。

所以要改标题就得自己做重定向。我现在的做法是标题定下来就不再动,措辞不满意宁可改正文。

顺带一提,文章的文件名和目录名不参与 URL 计算,那些可以随便改。

坑二:改了插件,构建成功但产物没变#

Astro 5 把 Markdown 的渲染结果缓存在 node_modules/.astro/ 下。问题在于,缓存失效的触发条件里不包含插件源码 —— 只有内容文件或 astro.config.mjs 变化才会让它失效。

于是会出现一种非常迷惑的现象:

  1. 改了 src/plugins/ 下的插件;
  2. astro check 通过,pnpm build 显示构建成功;
  3. 但产出的 HTML 和上一次字节级完全相同。

因为构建根本没重新渲染 Markdown,直接用了缓存。

解决办法是手动清掉缓存再构建:

Terminal window
rm -rf node_modules/.astro && pnpm build

判断自己是不是踩了这个坑,有个很省事的信号:正常的全新构建会打印一批内容同步日志,如果日志里那些行不见了,就说明走的是缓存。

坑三:无刷新跳转下,脚本必须幂等#

Swup 接管站内跳转后,页面不会整页刷新,只替换指定的容器。这带来一个容易被忽略的结果:

被替换容器里的内联 <script> 每次切页都会重新执行一遍。

如果脚本里写的是「给按钮绑一个点击事件」,那么访问得越多,绑定的监听器就越多,最后点一下按钮触发十几次。注册 IntersectionObserver、ResizeObserver 这类对象时同理,会不断堆积。

所以这类脚本一律要写成幂等的初始化函数:

  • 用 dataset 打个标记,已经初始化过就直接返回;
  • 注册新 observer 之前,先把上一个 disconnect() 掉。

另外,新页面里的 DOM 是重新插入的,事件需要重新绑定,通常得在 Swup 的 content:replace 钩子里再初始化一次。

坑四:正文标题层级会被构建期归一化#

为了让每篇文章有且只有一个 h1(也就是页面标题),我在构建流程里加了一个 remark 插件,会在渲染时做两件事:

  1. 如果正文的第一个标题是 h1,或者它的文字和 frontmatter 里的 title 完全一样,就删掉它;
  2. 把剩下的标题整体平移,让最浅的一级落在 h2。

结果是:无论我在 Markdown 里从 ## 还是 ### 开始写,渲染出来都是从 h2 开始,页面标题始终是唯一的 h1。写的时候不用纠结层级从哪起,但也意味着正文里不能用 h1 当章节 —— 那样会被当成重复标题删掉。

图片路径的三种写法#

这一点也值得单独说,因为三种写法含义完全不同,写错了不会报错,只是图出不来:

写法相对谁会不会被优化
assets/images/x.pngsrc/ 目录会,走 astro:assets
/images/x.pngpublic/ 目录不会,原样拷贝
./x.png当前 Markdown 文件会,走 astro:assets

放在 public/ 下的文件会被直接复制到产物里,适合那些不希望被处理的资源;放在 src/ 下的图片则会经过 Astro 的图片流水线,自动生成多尺寸、转成现代格式。

部署#

推送到 master 分支就会触发 GitHub Actions:构建 → 把产物 rsync 到 VPS。因为服务器上只跑 nginx 提供静态文件,所以整个流程就是一次文件同步,几秒钟结束。

唯一需要额外配置的是 404 页面 —— Astro 会产出一个 404.html,但还得在 nginx 里写一行 error_page 404 /404.html;,否则访问不存在的路径看到的仍是 nginx 的默认页。


以上就是这个站点的完整搭法。技术栈本身没什么新鲜的,真正花时间的是上面这四个坑 —— 它们共同的特点是:不报错、构建也成功,只是结果和你预期的不一样。这类问题最难查,所以专门记下来。

如果这篇对你有帮助,或者你也踩过类似的坑,欢迎在下面留言交流。

这个博客是怎么搭起来的:Astro + Fuwari 的四个真实坑
https://www.daitcc.top/posts/9068f072/
作者
Dait
发布于
2024-01-01
许可协议
CC BY-NC-SA 4.0
如果这篇文章对你有帮助或启发,可以请作者喝杯咖啡 ☕️