博客主题从 MemE 切换到 Stack 实录

一次完整的话题切换实操记录:从 MemE 换到 hugo-theme-stack,顺带把被钉死的 Hugo 老版本解锁。包含三个真实踩坑和 CI 迭代验证过程。

一、背景

博客原本用 MemE 主题(git submodule,钉在 2022 年的 v5.0.0)。MemE v5.0.0 用了旧版 resources.ToCSS API,与新版 Hugo 不兼容,导致 CI 工作流被迫把 Hugo 钉在 0.112.7——这是个 2023 年的老版本,越来越难维护,新特性也用不了。

目标:换成更现代的主题,并顺带解除旧 Hugo 版本锁。

二、选型

候选了三个主流主题,最终选 hugo-theme-stack:

  • 卡片式文章列表、左侧边栏、原生暗色模式切换
  • 维护活跃,文档完善
  • 要求 Hugo ≥ 0.157.0 extended,正好顺带升级

三、改动清单

1. 替换主题 submodule

移除 MemE,新增 Stack 并锁定到稳定 tag:

1
2
3
4
5
git submodule deinit -f themes/meme
git rm -f themes/meme
rm -rf .git/modules/themes/meme
git submodule add -b master https://github.com/CaiJimmy/hugo-theme-stack.git themes/stack
git -C themes/stack checkout v4.0.3

2. 重写 config.toml

从 1432 行的 MemE 配置精简到约 210 行。关键调整:

  • theme = "stack"
  • mainSections = ["zh"]:核心,让首页读 content/zh/(Notion Action 同步目录,不改 Action 也不改清理脚本)
  • [permalinks] zh = "/p/:slug/":用 Stack 默认 URL 风格,文章 URL 从 /zh/xxx/ 变 /p/xxx/
  • [menu] 改成 Stack 的 main + social 格式
  • 删除 MemE 专属的 [params]、[outputFormats]、[outputs] 等几百行

3. 重写 archetypes/notion.md

Notion Action 同步时套这个模板。改成 Stack 的 front matter 字段,两个关键点:

  • draft: false:Stack 默认 archetype 是 draft: true,不显式改 false 的话同步出的文章会被当草稿隐藏
  • category → categories(复数):Stack 模板用 .Params.categories 判断分类,单数 key 不会显示分类徽章

4. 升级 Hugo

工作流里 0.112.7 → 0.163.3,extended: true 保留。

四、踩坑记录

整个过程走了三轮 CI 迭代,每个坑都是一次失败构建。

坑 1:计划里的 Hugo 0.157.2 根本不存在

第一轮按计划填 hugo-version: '0.157.2',peaceiris/actions-hugo 直接报错:

1
Unable to find a compatible Hugo release asset for this runner.

查 Hugo releases 才发现:0.157 线只有 0.157.0,之后直接跳到 0.160+,根本不存在 0.157.1/0.157.2。改成实际存在的 0.163.3(成熟 .3 补丁版本,远高于 Stack 的 min 0.157.0)解决。

教训:版本号要查 releases 确认存在,别想当然填补丁号。

坑 2:菜单图标不在 Stack 内置集

第二轮 Hugo 装上了,但构建报:

1
2
ERROR Error: icon 'code.svg' is not found under 'assets/icons' folder
ERROR Error: icon 'notes.svg' is not found under 'assets/icons' folder

菜单里 技术 用了 icon = "code"、随笔 用了 icon = "notes",但 Stack 只内置 24 个 SVG(themes/stack/assets/icons/),不含 code/notes。改成内置图标:技术→categories、随笔→archives、关于→user。

教训:主题里引用的资源(图标、图片)要先确认主题是否自带,没有就得自己往 assets/ 放。

坑 3:languageCode 弃用警告

第三轮构建成功,但有 WARN:

1
WARN deprecated: project config key languageCode was deprecated in Hugo v0.158.0

修这个又踩了一层:顶层 languageCode 在 0.158 弃用,移到 [languages.zh].languageCode 后,0.163 又把这个键改名为 locale(连同 languageName → label)。最终用最新键名:

1
2
3
4
5
[languages]
    [languages.zh]
        locale = "zh-CN"
        label = "中文"
        weight = 1

额外风险:显式加 [languages.zh] 后,Hugo 可能把 content/zh/ 当成 zh 语言根目录(而非 section),导致 mainSections=["zh"] 失配、首页变空。本地用下载的 hugo 二进制构建验证过:仍是 section,首页 2 篇文章、/p/ URL 都没变,才敢推 CI。

五、验证方法

这次没用本地 hugo server 预览,直接靠 CI 验证:

  1. git push 后用 GitHub API 手动触发 workflow_dispatch
  2. 轮询 run 状态到 completed
  3. 失败就下载日志 zip,定位报错步骤,修复重推
  4. 成功后抓线上首页 HTML,核对 Stack 标记、文章链接、CSS/JS 资源是否 200

三轮迭代,每轮约 2–3 分钟,比反复起本地服务更快也更接近真实部署环境。

六、最终效果

线上 https://notion.dongxiaoqi.top/ 已确认:

  • Stack 外观:左侧边栏、卡片式文章列表、暗色模式切换
  • 首页正常显示 2 篇文章,URL 是 /p/xxx/
  • 文章页正文、标题、代码块、标签、阅读时长都正常
  • /tags/ 三个标签(Hugo / Notion / GitHub-Pages)正常
  • CSS(55KB)/ JS(8KB)资源都 200,无样式崩坏
  • 旧 /zh/xxx/ URL 已 404(符合预期,文章少无外链,可接受)

七、语言切换器的实现

主题切换上线后,照着 demo 站(demo.stack.cai.im)加了侧边栏的语言切换下拉框。这一节记录实现机制和一个非标准目录结构下踩的坑。

机制:hugo.IsMultilingual

Stack 的切换器在 themes/stack/layouts/_partials/sidebar/left.html,是一个