从使用者角度整理的 Hugo 常识,够用就行。

目录结构

blog/
├── hugo.toml          # 主配置文件(也可用 config.toml/yaml)
├── content/           # 所有内容(文章、页面)
│   ├── posts/        # 博客文章
│   └── about.md      # 单页(/about/)
├── layouts/           # 自定义模板(覆盖主题)
│   ├── _default/
│   │   ├── baseof.html   # 基础模板
│   │   ├── single.html   # 单页模板
│   │   └── list.html     # 列表页模板
│   └── partials/      # 可复用片段
├── themes/            # 主题目录
├── assets/            # 需要处理的资源
│   └── css/extended/  # 自定义 CSS(自动合并)
├── static/            # 静态文件(直接复制)
└── public/            # 构建输出(勿手动编辑)

构建原理

理解 Hugo 的构建流程,关键是看懂各目录的角色:

┌─────────────────────────────────────────────────────────────────┐
│                        Hugo 构建流程                             │
└─────────────────────────────────────────────────────────────────┘

  输入层(你写的)                    处理层                      输出层
  ──────────────                   ──────────                  ──────────

┌──────────────┐
│  hugo.toml   │─────────────────────┐
│  (配置)       │                     │
└──────────────┘                     ▼
                            ┌─────────────────┐
┌──────────────┐            │                 │
│  content/    │───────────▶│                 │
│  (Markdown)  │            │      Hugo       │
└──────────────┘            │     引擎        │
                            │                 │
┌──────────────┐            │  模板 + 内容    │
│  layouts/    │───────────▶│  + 资源 = HTML  │
│  (模板)       │            │                 │
└──────────────┘            │                 │                ┌──────────────┐
                            │                 │───────────────▶│   public/    │
┌──────────────┐            │                 │                │   (输出)     │
│  assets/     │───────────▶│                 │                │              │
│  (资源管道)   │            │                 │                │  index.html  │
└──────────────┘            │                 │                │  posts/      │
                            │                 │                │  css/        │
┌──────────────┐            │                 │                │  ...         │
│  static/     │───────────▶│                 │                │              │
│  (直接复制)   │            └─────────────────┘                └──────────────┘
└──────────────┘

各目录的角色

目录 角色 构建时行为
content/ 数据源 Markdown → 解析为 Page 对象
layouts/ 渲染模板 Go 模板引擎处理,绑定内容
themes/ 备用模板 被 layouts/ 覆盖
assets/ 资源管道 处理、压缩、指纹化
static/ 静态资源 直接复制到 public/
public/ 输出目录 最终静态站点

单篇文章的渲染链路

content/posts/my-post.md
        │
        ▼
┌───────────────────────────────────────┐
│ 1. 解析 Front Matter(title, date...) │
│ 2. Markdown → HTML                     │
│ 3. 确定 Content Type → 选择模板        │
└───────────────────────────────────────┘
        │
        ▼
layouts/_default/single.html  或  themes/xxx/layouts/_default/single.html
        │
        ▼
┌───────────────────────────────────────┐
│ 模板渲染:                              │
│  - {{ .Title }} → 文章标题              │
│  - {{ .Content }} → 正文 HTML           │
│  - {{ partial "toc.html" . }} → 目录    │
└───────────────────────────────────────┘
        │
        ▼
public/posts/my-post/index.html

模板选择逻辑

Hugo 按以下顺序查找模板(优先级从高到低):

1. layouts/posts/single.html    ←  针对 posts section
2. layouts/_default/single.html ←  默认单页模板
3. themes/xxx/layouts/posts/single.html
4. themes/xxx/layouts/_default/single.html

找到第一个匹配的模板后停止搜索。这就是为什么在 layouts/ 放同名文件可以覆盖主题模板。

资源管道流程

assets/css/extended/a.css
assets/css/extended/b.css
        │
        ▼  resources.Match "css/extended/*.css"
        │
┌─────────────────┐
│ resources.Concat│  →  合并为一个文件
└─────────────────┘
        │
        ▼
┌─────────────────┐
│ resources.Minify│  →  压缩(删除空格注释)
└─────────────────┘
        │
        ▼
┌─────────────────┐
│ fingerprint     │  →  生成哈希文件名(缓存控制)
└─────────────────┘
        │
        ▼
public/assets/css/stylesheet.abc123.css

模板优先级

layouts/              ←  最高优先级(你的自定义)
themes/PaperMod/layouts/  ←  主题默认模板

同名文件,layouts/ 覆盖 themes/。部分模板可单独覆盖,比如 layouts/partials/toc.html 只覆盖目录组件。

常用命令

hugo                  # 构建到 public/
hugo server           # 本地预览(默认 localhost:1313)
hugo server -D        # 包含草稿
hugo new posts/xxx.md # 新建文章

文章格式

---
title: "文章标题"
date: 2024-01-01
draft: false          # true = 草稿,不发布
tags: ["hugo"]
showToc: true         # 显示目录
---

正文内容...

样式覆盖方式

方式 说明
assets/css/extended/*.css 自动合并到主样式表
layouts/partials/extend_head.html 插入额外 <head> 内容
static/ 直接复制,用绝对路径引用

CSS 自动合并示例

PaperMod 主题在 head.html 中有这行:

{{- $extended := (resources.Match "css/extended/*.css") | resources.Concat "assets/css/extended.css" | resources.Minify }}

只要把 .css 放进 assets/css/extended/,Hugo 构建时自动加载,无需手动添加 <link> 标签。

配置要点

baseURL = 'https://example.com/'
theme = 'PaperMod'

[params]
  ShowToc = true        # 显示目录
  defaultTheme = "auto" # auto/light/dark

[markup.goldmark.renderer]
  unsafe = true         # 允许 HTML 标签

关键概念

概念 说明
Section content 下的目录,如 posts/
Page Bundle index.md + 同目录资源(页面级资源管理)
Shortcode 内容中的 {{< xxx >}},扩展 Markdown
Partial 可复用模板片段,{{ partial "xxx.html" . }}
Archetype hugo new 时的默认模板

资源管道

Hugo 可以对资源进行处理链:

{{- $css := (resources.Match "css/extended/*.css") 
    | resources.Concat "assets/css/extended.css" 
    | resources.Minify }}

处理流程:匹配文件 → 合并 → 压缩 → 输出


就这些,基本够用了。