前言

这篇是 Drifting-PaperMod 指南系列的第一篇,目标不是把某一个细节讲到最深,而是先把整条主线跑通:准备环境、初始化站点、接入主题、整理内容结构、写出第一篇文章、确认本地可用,再部署到 Cloudflare Pages。

Moments 这篇会先讲最小可用结构,标签筛选、评论联动和交互细节后面再单独展开。

Step 1 - 准备工作

先确认这台机器上有没有现成的 Git 和 Hugo,再决定要不要安装或升级。当前主题要求:

text
1Hugo Extended >= 0.146.0

先执行:

bash
1git --version
2hugo version

如果 git --version 能正常输出,说明 Git 已经在本机可用。

如果 hugo version 输出里带有 extended,并且版本不低于 0.146.0,就可以直接继续后面的步骤,不一定要重新安装。

只有在下面这些情况里,才需要安装或升级:

  • Git 命令不存在
  • Hugo 命令不存在
  • Hugo 不是 extended
  • Hugo 版本低于 0.146.0

安装或升级 Git

macOS:

bash
1xcode-select --install

Windows:

powershell
1winget install --id Git.Git -e --source winget

Linux:

bash
1sudo apt install git

如果你的 Linux 发行版不是 Debian / Ubuntu 系,把它换成自己发行版的包管理器命令即可。

安装或升级 Hugo

macOS:

bash
1brew install hugo

Windows:

powershell
1winget install Hugo.Hugo.Extended

Linux:

bash
1sudo snap install hugo

如果已经安装过 Hugo,但版本太低或不是 Extended 版,也可以直接升级:

  • macOS:brew upgrade hugo
  • Windows:winget upgrade Hugo.Hugo.Extended
  • Linux:使用当前发行版的包管理器升级对应包

处理完后,再执行一次:

bash
1git --version
2hugo version

如果终端提示找不到 hugo,优先检查 PATH 和实际调用位置:

  • macOS / Linux:which hugo
  • Windows PowerShell:Get-Command hugo

Step 2 - 初始化 Hugo 站点

先创建站点,再初始化 Git 仓库:

bash
1hugo new site myblog
2cd myblog
3git init

这里的 git init 不只是为了后面提交代码,更是为了下一步接入 submodule。没有 Git 仓库,git submodule add 就不会工作。

接着先创建一篇测试文章:

bash
1hugo new content posts/hello-world/index.md

我推荐从一开始就使用“一篇内容一个目录”的结构:

text
1content/
2└── posts/
3    └── hello-world/
4        └── index.md

这样后面放图片、附件、音频会更自然。

Hugo 新建内容通常会带 `draft: true`。本地预览时用 `hugo server -D`,准备正式发布时再改成 `draft: false`。

Step 3 - 用 Submodule 接入 Drifting-PaperMod

站点初始化好之后,直接按主题 README 的方式接入:

bash
1git submodule add --depth=1 https://github.com/DriftingBoats/Drifting-PaperMod.git themes/Drifting-PaperMod
2git submodule update --init --recursive

然后启用主题。Hugo 默认会生成 hugo.toml,如果你更习惯 YAML,也可以改成 hugo.yaml

yaml
1theme:
2  - Drifting-PaperMod

为什么这里推荐 submodule,而不是把主题代码直接拷进仓库?

  • 主题和站点仓库边界更清楚
  • 更新主题时不会把一堆主题文件混进正文提交
  • 换电脑或多人协作时,初始化流程更明确

如果你在另一台电脑上拉仓库,最省事的方式是:

bash
1git clone --recurse-submodules <your-repo-url>

如果仓库已经 clone 下来了,但 themes/Drifting-PaperMod 是空的,就补这一句:

bash
1git submodule update --init --recursive

Step 4 - 先配一套能长期用的 hugo.yaml

首篇不建议一上来就把所有参数都写满,但也不要只留一个 theme:。比较稳妥的做法,是先配一套足够完整、后面还能继续扩展的骨架。

下面这份配置片段已经覆盖了站点标题、首页介绍、菜单、社交图标、文章目录、滚动按钮和搜索所需的 JSON 输出:

yaml
 1baseURL: https://example.com/
 2languageCode: zh-cn
 3title: My Blog
 4
 5theme:
 6  - Drifting-PaperMod
 7
 8params:
 9  mainSections:
10    - posts
11
12  title: My Blog
13  author: Your Name
14
15  showtoc: true
16  tocopen: true
17  disableScrollToTop: false
18
19  homeInfoParams:
20    Title: "你好,欢迎来到我的博客"
21    Content: 这里放一句首页简介。
22
23  label:
24    text: "My Blog"
25    icon: /img/200x200.png
26    iconHeight: 35
27
28  assets:
29    favicon: /img/16x16.png
30    favicon16x16: /img/16x16.png
31    favicon32x32: /img/32x32.png
32    apple_touch_icon: /img/200x200.png
33
34  socialIcons:
35    - name: github
36      url: https://github.com/yourname
37    - name: rss
38      url: /index.xml
39
40menu:
41  main:
42    - identifier: archives
43      name: 文章
44      url: /archives/
45      weight: 20
46    - identifier: search
47      name: 搜索
48      url: /search/
49      weight: 30
50
51outputs:
52  home:
53    - HTML
54    - RSS
55    - JSON

这里最值得先记住的是:

  • params.mainSections 决定首页和归档页主要使用哪些内容类型
  • homeInfoParams 是首页介绍区
  • labelassets 负责站点标识和 favicon
  • showtoctocopen 控制文章目录
  • outputs.home 里的 JSON 是搜索页工作的前提

再补上搜索页和归档页

Drifting-PaperMod 已经自带搜索页和归档页布局,但你还需要在 content/ 下创建对应页面。

content/search.md

yaml
1---
2title: 搜索
3layout: search
4menu: main
5weight: 99
6ShowBreadCrumbs: false
7---

content/archives.md

yaml
1---
2title: 文章
3layout: archives
4summary: archives
5menu: main
6weight: 30
7---

这样菜单、搜索页和归档页才会真正串起来。

Step 5 - 内容结构:Posts、Moments 与 Front Matter

接好主题之后,最容易乱掉的不是配置,而是内容结构。把 postsmoments、页面文件和资源放置方式先定下来,后面写内容会轻松很多。

推荐的项目整体结构

一个和这套主题比较匹配的结构大致是这样:

text
 1myblog/
 2├── content/
 3│   ├── posts/
 4│   │   ├── _index.md
 5│   │   └── my-first-post/
 6│   │       ├── index.md
 7│   │       └── cover.png
 8│   ├── moments/
 9│   │   ├── _index.md
10│   │   └── 260310-200410/
11│   │       ├── index.md
12│   │       └── Pasted image 20260310200413.jpg
13│   ├── search.md
14│   └── archives.md
15├── static/
16│   └── img/
17├── themes/
18│   └── Drifting-PaperMod/
19└── hugo.yaml

这里可以这样理解:

  • content/posts/ 放普通文章
  • content/moments/ 放 moments 内容
  • content/search.mdcontent/archives.md 分别对应搜索页和归档页
  • static/img/ 放全站复用资源
  • themes/Drifting-PaperMod/ 是主题 submodule
  • hugo.yaml 是站点总配置入口

posts/_index.mdmoments/_index.md

在这套结构里,两个 _index.md 分别负责不同的 section。

content/posts/_index.md

yaml
1---
2title: "文章"
3layout: posts
4summary: posts
5---

这个文件负责文章列表页。

content/moments/_index.md

yaml
 1---
 2title: 瞬间
 3build:
 4  render: always
 5cascade:
 6  - build:
 7      list: local
 8      publishResources: true
 9      render: never
10menu: main
11weight: 10
12---

这个文件负责 moments 列表页,同时决定子页面不单独渲染,但资源继续发布。

Posts 怎么组织

普通文章建议统一使用 leaf bundle:

text
1content/posts/my-first-post/
2├── index.md
3└── cover.png

这种结构的好处是内容和资源天然绑定,迁移、备份和后续压缩图片都更方便。

Moments 怎么组织

Moments 也推荐使用同样的 leaf bundle 结构:

text
1content/moments/260310-200410/
2├── index.md
3└── Pasted image 20260310200413.jpg

如果是音频或视频,也直接和 index.md 放在同一目录:

text
1content/moments/250625-154957/
2├── index.md
3└── M5000034UIUo36zCqC.mp3

主题里的 layouts/moments/list.html 会直接渲染 content/moments/ 下的 .RegularPages,所以这种目录结构最省心。

普通文章的 Front Matter

对于普通文章,我建议直接按这套字段起步:

yaml
 1---
 2title: 我的第一篇文章
 3slug: my-first-post
 4date: 2026-03-10T22:00:00+08:00
 5lastmod: 2026-03-10T22:00:00+08:00
 6tags:
 7  - Hugo
 8categories: 博客建站
 9series: Drifting-PaperMod 指南
10summary: 这里是一段文章摘要。
11draft: true
12---

最关键的字段是:

  • title
  • slug
  • date
  • draft

如果按这个仓库的习惯继续完善,常用字段还包括:

  • lastmod
  • tags
  • categories
  • series
  • summary

正式发布前,再把 draft: true 改成 draft: false

Moments 的 Front Matter

单条 moment 通常不需要 title,更常见的是这种更轻量的写法:

yaml
1---
2date: 2026-03-10T20:04:10+08:00
3lastmod: 2026-03-10T20:04:14+08:00
4slug: 260310-200410
5tags:
6  - 杂记
7---

Step 6 - 本地验证这套主题有没有真的接好

别急着上线,先把本地验证做完。

启动开发服务器:

bash
1hugo server -D

至少检查这几类页面:

  • 首页是否正确显示站点标题、首页简介和菜单
  • 文章页是否能正常渲染正文和目录
  • /search/ 是否能打开
  • /archives/ 是否能按时间归档文章
  • /moments/ 是否能正常显示 moments 列表

最后再跑一次生产构建:

bash
1hugo --gc --minify

如果这一步能正常生成 public/,说明这套 Hugo + 主题基础链路已经通了。

Step 7 - 主题维护:怎么更新 Drifting-PaperMod

如果主题仓库后面有更新,不需要删除主题目录重装,正常更新方式就是:

bash
1git submodule update --remote --merge themes/Drifting-PaperMod
2git add themes/Drifting-PaperMod
3git commit -m "theme: update Drifting-PaperMod"
4git push

更新前我建议先看一下当前状态:

bash
1git status
2git submodule status --recursive

更新主题时最容易踩的坑

1. 不要长期直接改 submodule 里的文件

如果你直接在 themes/Drifting-PaperMod 里改模板、样式和脚本,后面更新时会更容易冲突,也更容易把自己的改动弄丢。

更稳妥的做法是:

  • 站点级覆盖优先放根目录自己的 layouts/assets/static/
  • 如果确实要长期维护主题本体改动,先 fork 一份自己的主题仓库,再把 submodule 指向自己的 fork

2. 更新前先保证工作区干净

如果主仓库或 submodule 里本来就有未提交改动,更新后很难判断哪些是上游更新,哪些是自己的本地改动。

3. 更新后同步检查 Hugo 版本

主题 README 当前写的是 Hugo Extended >= 0.146.0。如果主题后续抬高要求,而你本地或部署环境还停在旧版本,就可能出现模板函数不兼容或构建失败。

4. 更新后一定先本地构建

先跑:

bash
1hugo server -D
2hugo --gc --minify

确认首页、文章页、搜索页、归档页和 moments 页都正常,再 push。

Step 8 - 上线方式:部署到 Cloudflare Pages

本地确认没有问题后,再接 GitHub 和 Cloudflare Pages。

先把站点推到 GitHub:

bash
1git add .
2git commit -m "init: create Hugo site"
3git branch -M main
4git remote add origin https://github.com/<your-username>/<your-repo>.git
5git push -u origin main

然后在 Cloudflare Pages 里导入这个 GitHub 仓库,使用最小可用配置:

  • Production branch:main
  • Build command:hugo
  • Build directory:public

同时在项目环境变量里手动设置:

text
1HUGO_VERSION=0.157.0

Production 和 Preview 两边都建议配上,不要只配一个环境。

Build command 可以写成 hugo -b $CF_PAGES_URL,因为 Hugo 的 baseURL 会影响绝对链接和 canonical URL。对还没绑定正式域名,或者很依赖预览环境的站点,这个写法更稳。

如果你启用了首页热力图,也不需要再在 Cloudflare Pages 的构建命令里额外追加 pip installpython heatmap.py。当前热力图数据已经在 hugo 构建阶段由模板直接生成,保持纯 Hugo 构建即可。

后面还可以继续补什么

这篇先把主题首篇最关键的主线跑通,后面再往上叠功能会更自然。下一批适合单独展开的主题能力有:

  • Moments 页面交互
  • Waline 评论
  • 首页热力图
  • 常用 Shortcodes

参考链接