我的旧博客基于 Hugo 0.111.3 + hugo-coder 主题运行了三年多,最近升级到 Hugo 0.164.0 并换用了 PaperMod 主题。整个过程比预想的顺利,但还是踩了几个坑,记录一下供有类似需求的朋友参考。

迁移背景

旧博客新博客
Hugo 版本0.111.30.164.0
主题hugo-coderPaperMod
配置文件config.tomlhugo.yaml
域名blog.wangyu.linkwangyu.link

两个版本隔了约 50 个 minor 版本,配置格式从 TOML 切换到 YAML,主题也完全不同。迁移的核心工作就是三个:内容搬迁配置映射兼容性处理

内容搬迁

这一步最简单——直接把 content/ 目录下的所有 markdown 文件复制过去就行。

cp -r personal-blog/content/* NormanBlog/content/

我的旧博客有 90+ 篇文章和 3 个独立页面(About、Projects、List),frontmatter 都是标准的 Hugo 格式,不需要任何修改就能被新版本识别。

静态资源同理:

cp -r personal-blog/static/* NormanBlog/static/

favicon、avatar、site.webmanifest 等直接搬过去即可。

配置映射:从 hugo-coder 到 PaperMod

这才是迁移的重头戏。两个主题的参数体系完全不同,需要逐一对照映射。

基本配置

# hugo.yaml (PaperMod)
baseURL: https://wangyu.link/
locale: en              # Hugo 0.158+ 废弃了 languageCode
title: Norman's Blog
theme: ["PaperMod"]
paginate: 20

旧配置中的 languagecode = "en" 在 Hugo 0.158.0 之后被废弃了,需要改成 locale: en。如果继续用 languageCode,构建不会失败,但会一直弹出 deprecation 警告。

个人信息与首页

hugo-coder 用简单的 key-value 展示个人信息:

[params]
  author = "Norman Wang"
  info = "Front-end / Electronjs Development Engineer"
  avatarurl = "images/avatar.png"

PaperMod 有两种首页模式:profileModehomeInfoParams。我选择了更简洁的 homeInfoParams

params:
  author: Norman Wang
  homeInfoParams:
    Title: "Norman Wang"
    Content: "Front-end / Electronjs Development Engineer"
  label:
    text: "Norman's Blog"
    icon: /images/avatar.png
    iconHeight: 35

社交链接

这是最容易踩坑的地方。hugo-coder 使用 Font Awesome 图标类名:

[[params.social]]
  name = "Github"
  icon = "fa fa-github fa-2x"
  url = "https://github.com/blogwy"

PaperMod 则内置了自己的 SVG 图标集,通过 name 字段匹配:

params:
  socialIcons:
    - name: github
      url: "https://github.com/blogwy"
    - name: email
      url: "mailto:wangyu@wangyu.link"
    - name: rss
      url: "https://..."

PaperMod 支持的图标名称包括 githubemailrssx(Twitter)、stackoverflowlinkedin 等几十种——不需要引入任何外部图标库。

代码高亮

旧配置:

[markup.highlight]
  style = "github-dark"

PaperMod 的 sample config 提示需要额外设置 pygmentsUseClasses: true,但在我的实际测试中,直接保留 highlight 配置就能正常工作:

markup:
  highlight:
    style: github-dark

菜单 & 分类

这部分两个主题的配置方式很接近,几乎可以直接平移:

menu:
  main:
    - identifier: blog
      name: Blog
      url: /posts/
      weight: 1
    - identifier: projects
      name: Projects
      url: /projects/
      weight: 2
    # ...

taxonomies:
  category: categories
  series: series
  tag: tags
  author: authors

兼容性问题的坑

1. Goldmark 不再默认允许原始 HTML

Hugo 0.111.3 中,Goldmark 渲染器默认允许 Markdown 中嵌入原始 HTML。0.164.0 出于安全考虑默认关闭了。我的几篇旧文章里嵌了 <iframe><style> 标签,构建时会报:

WARN  Raw HTML omitted while rendering "..."

而且 HTML 标签被直接删掉,页面内容不完整。解决方案是在配置中显式开启:

markup:
  goldmark:
    renderer:
      unsafe: true

2. 主题模板的废弃 API 调用

PaperMod 的部分模板使用了 .Language.LanguageCode.Language.LanguageDirection,这两个 API 在 Hugo 0.158.0 被标记为废弃。每次构建都会弹出警告,但不影响功能

这个问题需要等 PaperMod 主题更新模板才能彻底解决。如果你在意干净的构建输出,可以自行修改主题模板,将 .Language.LanguageCode 替换为 .Language.Locale.Language.LanguageDirection 替换为 .Language.Direction

3. 主题子模块的版本

旧博客的 .gitmodules 里还残留了 ananke 和 hugo-coder 两个子模块。迁移后只需要保留 PaperMod:

[submodule "themes/PaperMod"]
    path = themes/PaperMod
    url = https://github.com/adityatelange/hugo-PaperMod.git

主题特性对比

PaperMod 相比 hugo-coder 多了一些开箱即用的能力:

  • 暗色/亮色模式自动切换(跟随系统 + 手动切换按钮)
  • 搜索(基于 Fuse.js 的客户端搜索,零依赖)
  • 代码复制按钮
  • 社交分享按钮
  • 面包屑导航
  • 阅读时间 & 字数统计
  • 文章封面图

这些功能在 hugo-coder 上要么不支持,要么需要手动配置。

迁移检查清单

如果你也需要做类似的迁移,可以按以下顺序操作:

  1. 备份旧博客 —— 整个目录打个 zip,随时可以回滚
  2. 复制内容 —— content/static/ 直接搬
  3. 配置映射 —— 对照新旧主题文档逐项迁移
  4. 构建验证 —— hugo 命令跑一遍,看有没有报错
  5. 本地预览 —— hugo server -D 检查页面效果
  6. 修复警告 —— 处理 deprecation 和兼容性问题
  7. 部署上线 —— 确认无误后推送

总结

整个迁移从探索结构到构建成功花了不到半小时。Hugo 的向后兼容性做得相当不错,三年前的 markdown 内容完全不需要修改。主要的精力花在适配新主题的配置参数上——这部分如果直接参考主题的 exampleSite 配置模板,可以省很多时间。

如果你也在考虑从老版本 Hugo 迁移,放心动手吧,比想象中简单得多。