跳到主要内容
  1. 文章/

使用 Hugo+Congo 构建个人站点

·8 分钟

近期用 Hugo 配合 Congo 主题搭建了个人博客站点,经过简单配置和“装修”后目前已经上线运行。

本文简要记录配置与部署过程中遇到的问题与解决方案,并谈谈对 Hugo & Congo 设计思想的理解。

1. 配置过程 #

Hugo 的整体配置流程较为简单,大部分问题参考官方文档即可快速解决,因此这一环节仅做简要记录:

  1. 本地安装 Hugo,创建站点。
  2. 使用 Git Submodule 的方式安装 Congo 主题。
  3. 参照 Congo 文档完成配置: 基本配置 · Congo
  4. 将站点项目提交到 GitHub。
  5. 在 Vercel 上创建项目并关联 GitHub 仓库,配置自动部署。
  6. 针对站点做简单装修和扩展优化:
    1. 主页菜单添加 RSS
    2. 集成 Artalk 评论系统
    3. 集成 Google Analytics
    4. Git 忽略 public 和 resources
    5. 自定义 favicon

完成后,无论发布文章还是修改站点,只需将变更 push 到 GitHub,Vercel 即可自动部署。整个工作流自动、简洁,可将更多精力放在内容生产上,而且 Vercel 的免费额度足以支撑个人站点。

2. 过程问题排查和解决 #

以下为部署过程中遇到的问题,均通过搜索和 AI 辅助解决。

多语言相关 #

修改默认语言代码 #

我的母语为中文,借助当前强大的 LLM,可以轻松将文章转换成英文,创造更多连接的可能性。

Hugo 与 Congo 对多语言支持良好,且已支持简体中文。但 Congo 默认的简体中文语言代码为 zh-Hans,在日常配置中略显繁琐。

为简化使用,我将 themes/congo/i18n/zh-Hans.yaml 复制到项目根目录的 i18n/ 并重命名为 zh.yaml(即 i18n/zh.yaml)。这样等价于将简体中文的语言代码调整为 zh,同时可直接编辑 i18n/zh.yaml 来覆盖主题默认的简体中文翻译。

双语文章的内容组织形式 #

对于多语言内容的组织,Hugo 提供多种方式。我采用最直观的“文件名配置法”:在同一个页面包目录下,用 *.语言代码.md 区分不同语言的页面。

例如一篇文章“我的精彩旅行”,目录结构如下:

content/posts/my-awesome-trip/

  • index.zh.md(中文内容)
  • index.en.md(英文内容)
  • featured.jpg(中英文共享的图片)

需要在 index.zh.mdindex.en.md 中设置相同的 translationKey。Hugo 的多语言引擎会自动处理语言切换、URL 前缀、站点地图(会生成一个指向各语言 sitemap 的 sitemap index 文件)、分类与标签等细节。

修正中文阅读时间错误的问题 #

Hugo 支持“文章阅读时长”的计算和显示。但默认配置下,中文文章的阅读时长偏差较大,主要原因有二:

  • Hugo 默认基于英文阅读速度(约 200 词/分钟),对中文不够准确。
  • 中、日、韩文属于 CJK 语言,这类语言的字数计算与英文不同,需要特别配置与声明。

解决方法如下。

步骤 1:配置 Hugo 支持 CJK 语言 #

config/_default/hugo.toml 中开启 CJK 支持:

# 其他配置...
baseURL = "https://example.com/"
defaultContentLanguage = "zh"
hasCJKLanguage = true  # 支持中文、日文、韩文字符统计
步骤 2:配置中文阅读速度 #

config/_default/languages.zh.toml 中设置中文阅读速度:

languageCode = "zh"
languageName = "中文"
languageDirection = "ltr"
weight = 1

title = "网站标题"

[params]
  dateFormat = "2006-01-02"
  reading_speed = 400  # 中文阅读速度:400 字/分钟
  # 其他参数...
步骤 3:创建自定义阅读时间模板 #

创建文件 layouts/partials/meta/reading-time.html,覆盖 Congo 主题默认模板:

{{- $readingSpeed := .Site.Language.Params.reading_speed | default 200 -}}
{{- $wordCount := .WordCount -}}
{{- $readingTime := math.Ceil (div (float $wordCount) (float $readingSpeed)) -}}
<span title="{{ i18n "article.reading_time_title" }}">
  {{- i18n "article.reading_time" (dict "Count" $readingTime) | markdownify | emojify -}}
</span>
{{- /* Trim EOF */ -}}

该模板获取文章字数 $wordCount,除以 reading_speed 后向上取整,并按多语言模板显示。

Vercel 部署 #

Build 时找不到 layout 文件 #

首次部署时出现如下 WARN 与 ERROR:

WARN  found no layout file for "html" for kind "page": You should create a template file which matches Hugo Layouts Lookup Rules for this combination.
WARN  found no layout file for "html" for kind "taxonomy": You should create a template file which matches Hugo Layouts Lookup Rules for this combination.
WARN  found no layout file for "html" for kind "term": You should create a template file which matches Hugo Layouts Lookup Rules for this combination.
WARN  found no layout file for "html" for kind "section": You should create a template file which matches Hugo Layouts Lookup Rules for this combination.
ERROR render of "/404" failed: ".../themes/congo/layouts/baseof.html:1:4": execute of template failed: template: 404.html:1:4: executing "404.html" at <partial "functions/warnings.html" .Site>: error calling partial: partial "functions/warnings.html" not found

Error: error building site: render: failed to render pages: render of "/" failed: ".../themes/congo/layouts/baseof.html:1:4": execute of template failed: template: index.html:1:4: executing "index.html" at <partial "functions/warnings.html" .Site>: error calling partial: partial "functions/warnings.html" not found
报错解读 #
  • 构建时找不到任何布局(layout)文件。
  • 渲染需要的 warnings.html partial 也未找到。
原因 #

主题以 Git Submodule 引入。将仓库推送到 GitHub 时只包含了指向主题的“指针”,Vercel 默认不会拉取子模块,导致构建时 themes/congo 为空,Hugo 无法找到主题文件。

解决方案 #

在 Vercel 项目中添加环境变量以拉取子模块:

  • Name: GIT_SUBMODULES_STRATEGY
  • Value: 1

保存后重新部署。Vercel 会执行 git submodule update --init --recursive,主题文件被完整拉取,构建即可成功。

部署后页面错乱 #

站点可访问,但页面布局错乱。浏览器控制台显示 main.bundle.min.css 加载失败。

原因 #
  1. Hugo 构建时的 baseURL 设为 https://yandong.xyz/(无 www),生成的资源链接是绝对路径,如 https://yandong.xyz/css/main.bundle.min.css
  2. Vercel 域名配置将根域名 yandong.xyz 重定向到 www.yandong.xyz
  3. 页面在 www 域名下加载非 www 域名资源发生重定向与同源策略冲突,导致样式未加载。
解决方案 #

统一 Hugo 的 baseURLhttps://www.yandong.xyz/,与 Vercel 最终域名一致。重新部署后,资源链接与页面同源,请求不再跨域或重定向,问题消失。

3. 对 Hugo & Congo 设计理念的理解 #

组合 > 继承 #

Hugo 的渲染查找顺序为:项目 layouts > 主题 layouts > Hugo 内置。通过“组合式覆盖”替代传统的“继承”关系。就像“图层”的概念:只需在最顶层(项目)绘制要修改的部分,即可覆盖底层内容,无需修改或继承底层,实现高度自由且稳健的自定义。

配置分离 #

Hugo 与 Congo 将大量开关与选项(如社交链接、评论系统)放入配置文件而非模板硬编码。Congo 进一步细化常用配置:

  • languages.[语言].toml 管理多语言
  • menu.[语言].toml 管理菜单
  • params.toml 管理主题外观与参数

以内容为中心的资源组织 #

传统做法常将内容(.md)与资源(图片)分离在 content/static/。Hugo 的页面包(Page Bundles)理念是:资源应与消费它的内容共存于同一目录。文章与配图在逻辑上不可分,在文件系统上亦应一致,这提升了可移植性与可维护性,并便于相对路径引用。

包裹复杂性 #

针对多语言、图片处理、多站点输出等复杂问题,Hugo 提供原生方案,用户无需过多处理底层细节与性能、兼容性问题。

4. 实践原则 #

基于上述理解,我个人会遵循形以下实践原则:

永远不要直接修改主题文件 #

始终在项目根目录的 layouts/assets/static/ 中创建文件来覆盖或补充主题;配置集中于项目的 .toml。使项目与主题解耦,后续升级主题时无需担心自定义丢失。

拥抱页面包 #

只要文章包含图片或其他资源,就为其创建目录,并将内容文件命名为 index.md。使用相对路径 ![…](./image.jpg) 引用资源,使内容单元(文章 + 图片)独立、完整、易维护,便于备份与迁移。

遵循 Congo 推荐的项目结构 #

为充分利用默认配置,你的项目结构应类似:

.
├── assets
│   └── css
│       └── compiled
│           └── main.css  # 由构建生成
├── config  # site config
│   └── _default
├── content  # site content
│   ├── _index.md
│   ├── projects
│   │   └── _index.md
│   └── blog
│       └── _index.md
├── layouts  # custom layouts for your site
│   ├── partials
│   │   └── extend-article-link.html
│   ├── projects
│   │   └── list.html
│   └── shortcodes
│       └── disclaimer.html
└── themes
    └── congo  # git submodule or manual theme install

以上为个人实践记录与理解,希望对你有所帮助。如遇到其他问题,欢迎留言交流。