这是本节的多页打印视图。 .
十分钟上手
- 1: 仓库导览
- 2: 从零建站与其它安装方式
这条路径不从空目录开始,而是克隆你正在读的这个站点,删掉不需要的部分,再替换成你自己的信息。本站是 OINK 的回归站,包含每个组件与每种页面类型,并与主题保持同版本;从它开始删减,比从空目录逐项补配置与示例少写很多。
前提:一台能安装 Hugo Extended 与 Go 的机器、一个 GitHub 账号、十分钟。不需要 Node.js,也不需要其它前端工具链。
结果
完成后得到一个双语文档站:左侧栏是你的目录树,右侧是本页目录,顶栏有全文搜索与命令面板,深浅色跟随系统;一份 Markdown 同时产出网页、打印页、纯 Markdown 与 RSS;托管在 GitHub Pages 上。

步骤
-
安装 Hugo Extended 与 Go
除 Git 之外需要两样。Hugo Extended 必须是
0.160.1或更高版本:标准版 Hugo 没有内置 Sass 编译器,编译不了主题样式,构建失败。Go 用于解析模块:OINK 以 Hugo Module 发布,Hugo 通过 Go 的模块机制下载并校验github.com/pgsty/oink。macOSLinuxWindows安装完成后核对一次,输出里必须出现
extended: -
克隆文档站并预览
打开 http://localhost:1313/,中文站在 http://localhost:1313/zh/。第一次启动会下载主题模块(几秒到一分钟,取决于网络),之后修改文件是毫秒级热重载。
已提交的
go.mod固定了主题版本,克隆之后即可构建,不需要额外的安装脚本。说明仓库里的
Makefile只是几条命令的别名。make dev与make check通过HUGO_MODULE_REPLACEMENTS使用同级的../oink主题 checkout;make build与make serve始终使用go.mod固定的公开版本。新站点用hugo server即可。 -
替换站点信息
站点身份:全部在
hugo.yml里。baseURL用的是 YAML 锚点,实际地址写在params.productionURL上,只改这一处:hugo.ymllanguages.en.title与languages.zh.title会覆盖顶层title,两处一起改。参数逐项的含义与默认值见配置总览。删掉本站专用的配置:保留它们会让你的站点指向 OINK 的仓库与账号。
hugo.yml里的键怎么处理 services.googleAnalytics.idOINK 的统计 ID,删掉;需要统计时换成你自己的 params.commentsgiscus 指向 pgsty/oink.pgsty.com的讨论区,整段删掉或换成你的仓库params.tdVersionparams.versionparams.version_menuparams.versionsOINK 的版本菜单,删掉 params.github_project_repo主题仓库链接,删掉 languages.<lang>.menus.main顶栏菜单指向 /docs/tutorial这类本站栏目,按你的目录重写换 Logo 与图标:替换这三个文件,文件名保持不变,主题按文件名挂载:
static/static/logo.svg是本站自己的品牌组合标,没有参数指向它:删掉,或者换成你的横向字标再设params.wordmark。替换内容:
content/docs/是 OINK 自己的主题文档,整棵删除,写你自己的第一页:content/docs/_index.mdcontent/blog/可以留一篇当模板,也可以整个目录删除(删除后把menus.main里的blog项一并删掉)。哪些目录必须保留、哪些是文档站自用,见仓库导览。只做英文站:删除
languages.zh整段与所有.zh.md文件,languages缩成一段:hugo.yml保留双语或换成其它语言对,见多语言。
-
部署
在 GitHub 上新建一个空仓库,把本地历史换成你自己的:
仓库自带
.github/workflows/pages.yml:推到main分支即构建并发布,也可以在 Actions 页面手动触发(workflow_dispatch)。它固定 Hugo Extended 与 Go 的版本,用--printPathWarnings --panicOnWarning构建,baseURL由 GitHub Pages 提供,因此发布到example.github.io/product-docs/这类子路径也不必改配置。在仓库的 Settings → Pages → Build and deployment → Source 选 GitHub Actions。默认值是
Deploy from a branch,不改这一项 workflow 会在部署步骤失败。删除scripts/后要改 workflowpages.yml中的Verify advertised and pinned release match一步运行node scripts/check-release-pin.mjs,校验站点公告的版本与go.mod固定的版本一致。删掉scripts/之后,把这一步与Set up Node.js一并从pages.yml移除。Cloudflare Pages、Netlify、Nginx 与离线打包见发布上线:构建命令都是
hugo --gc --minify,区别只在baseURL与环境变量。
验证
本地运行一次生产构建。它比开发服务器严格,路径告警会让构建失败:
输出 Total in … 且没有 WARN / ERROR 即通过。再对照预览核对:
- 顶栏是你的站名与 Logo,浏览器标签页是你的 favicon
- 侧栏是你自己的目录树,每页都能打开
- 按 Ctrl 加 K(macOS 上是 ⌘ 加 K)打开命令面板,能搜到刚写的页面
- 页面标题右侧的菜单里,「编辑当前页面」指向你自己的仓库,不是
pgsty/oink.pgsty.com - 部署后 GitHub 仓库 Actions 页面里的
Deploy Oink site to GitHub Pages是绿的
构建报错见排错与检查。
下一步
- 仓库导览 — 克隆下来的每个目录是什么,哪些可以删。
- 编写页面 — 一页文档的组成:front matter、标题锚点、链接与图片。
- 组件总览 — 提示块、标签页、参数表、文件树等,每个组件一页。
- 品牌外观 — 主色、字体预设、页宽与自定义样式。
- 发布上线 — GitHub Pages 之外的托管方式与验收清单。
给编码助手的指令
上面四步可以交给编码助手(Claude Code、Codex 等)执行。复制下面这段指令,把方括号里的三处替换为你自己的信息:
建好的站点便于助手读取:每页都有 .md 纯文本输出,站点根有 llms.txt,页面标题右侧的菜单里有「复制 Markdown 文本」与「在 Claude 中打开」。见 Agent 支持。
不从这个仓库起步、要从空目录搭建,见从零建站与其它安装方式。
相关
- 仓库导览 — 每个目录是什么、删的顺序
- 从零建站与其它安装方式 —
hugo mod init起步、submodule 与离线安装 - 本地预览 —
hugo server的常用开关与草稿预览 - 发布上线 — 各家托管的配置与验收清单
- 排错与检查 — 构建、语言、搜索、平台四类常见错误
1 - 仓库导览
本页逐项说明 pgsty/oink.pgsty.com 克隆下来的每个文件与目录:哪些必须保留、哪些替换为你自己的信息、哪些是文档站自用可以整棵删除,并给出一个安全的删除顺序。
主题代码不在这个仓库里:它是 go.mod 固定的一个 Hugo Module,存放在 Go 的模块缓存中。这个仓库只有内容、配置与站点自己的少量覆盖。
顶层结构
克隆下来的 my-docs/
- my-docs/
- hugo.yml站点唯一配置:身份、语言、菜单、参数、模块导入
- go.mod固定主题版本
- go.sum主题模块的校验和
- content/全部内容,目录结构就是侧栏结构
- _index.md首页;_index.zh.md 是它的中文对等页
- search.mdGoogle 自定义搜索的结果页,用不到可删
- docs/文档树:OINK 自己的主题文档
- blog/博客:工程记录与版本发布
- assets/要经 Hugo 处理的资源
- scss/站点样式覆盖,三个 partial
- images/需要缩放裁切的图片
- parts/include shortcode 引入的 Markdown 与 YAML 片段
- static/原样复制到站点根,不做处理
- logo.svg品牌组合标,没有参数指向它
- favicon.svg浏览器标签页图标
- favicon.ico
- apple-touch-icon.pngiOS 添加到主屏
- images/截图与示意图
- layouts/站点模板覆盖:只覆盖最窄的那一个
- _shortcodes/站点自己的 shortcode
- data/数据驱动的页面
- home/首页分区:en.yaml / zh.yaml
- landing/Landing 页数据
- download/发布与下载页数据
- .github/
- workflows/pages.yml 部署;另外两个是本站回归测试
- tests/文档站自用:Playwright、goldens、构建断言
- browser/Playwright 规格
- hugo-build/构建断言
- md-output/Markdown 输出 goldens
- alt-site/备用配置构建
- favicons/
- release-pin/
- fixtures/
- scripts/文档站自用:翻译对等与链接检查
- check-doc-translations.mjs
- check-markdown-style.mjs
- check-rendered-links.mjs
- check-rendered-markdown.mjs
- check-release-pin.mjs
- Makefilebuild / serve 直接调 Hugo;dev / check 指向同级 ../oink
- package.json测试工具链,站点构建用不到
- package-lock.json
- playwright.config.mjs
- agent-docs.config.ymlAgent 文档评分工具的配置
- AGENTS.md给编码 Agent 的仓库说明
- TRANSLATION.md双语翻译流程
- CONTRIBUTING.md
- README.md
- LICENSEApache-2.0,站点代码
- LICENSE-CC-BY-4.0内容许可
- NOTICE
上面没有列出的还有 .gitignore、.gitattributes、.nvmrc、.npmrc,以及被 .gitignore 排除的生成物:public/(构建产物)、resources/(Hugo 资源缓存)、node_modules/。后一组不进版本库。
仓库里没有 i18n/:界面文字(「上一页」「本页目录」这类)由主题的 32 份语言文件提供。要改其中某一句,在站点根目录建 i18n/zh.yaml,只写需要覆盖的键。
各项的处理方式
| 路径 | 是什么 | fork 后怎么处理 |
|---|---|---|
hugo.yml |
站点的唯一配置文件,没有 config/ 目录也没有分环境覆盖 |
替换为你的信息:身份、语言、菜单、品牌 |
go.mod go.sum |
固定主题版本并记录校验和 | 必须保留,一起提交 |
content/ |
全部内容;目录结构决定侧栏结构 | 必须保留;里面的 docs/、blog/ 换成你自己的 |
content/search.md |
layout: search 的整页搜索结果,只在配了 Google 自定义搜索(params.gcs_engine_id)时才有内容 |
用主题自带的本地搜索时可以删 |
assets/scss/ |
站点样式覆盖(_variables_project.scss 等) |
要改配色字体就保留,不改可以清空 |
assets/images/ |
需要 Hugo 处理(缩放、裁切)的图片 | 换成你自己的 |
assets/parts/ |
include shortcode 引入的片段 |
随引用它的页面一起替换或删除 |
static/ |
原样复制到站点根 | 替换为你的:logo、favicon、截图 |
layouts/_shortcodes/ |
本站自己的四个 shortcode,当前内容里已无引用 | 可删 |
data/home/ |
首页分区数据(Hero、能力面板) | 改成你的;删除后首页退回普通页面 |
data/landing/ data/download/ |
Landing 页与发布下载页的数据 | 用不到就删 |
.github/workflows/pages.yml |
推到 main 就构建并发布到 GitHub Pages |
保留,按你的仓库改 |
.github/workflows/site-checks.yml browser-quality.yml |
本站的回归测试流水线 | 文档站自用,可删 |
tests/ scripts/ playwright.config.mjs package.json package-lock.json |
本站的回归测试与检查工具链 | 文档站自用,可删 |
Makefile |
主题与站点共同开发的快捷方式(要求同级有 ../oink) |
文档站自用,可删 |
AGENTS.md TRANSLATION.md CONTRIBUTING.md agent-docs.config.yml |
本站的协作约定 | 换成你自己的,或删 |
README.md LICENSE LICENSE-CC-BY-4.0 NOTICE |
说明与许可 | 换成你自己的 |
.nvmrc .npmrc |
Node 版本与 npm 配置 | 随 package.json 一起删 |
这个仓库里的 package.json、tests/、scripts/ 用于维护文档站本身。你的站点构建只有一条命令:hugo --gc --minify。
删除顺序
顺序是先删外围、再删内容、最后清数据。每删一步构建一次,出问题时能定位到具体步骤。
-
删脚手架
这一批与站点渲染无关,删除后不影响任何页面。
删除
scripts/之后必须改.github/workflows/pages.yml:把Set up Node.js与Verify advertised and pinned release match两步删掉,否则部署会在该步骤失败。 -
删示例内容
content/docs/是 OINK 自己的主题文档,content/blog/是它的工程博客,与你的产品无关。同时改
hugo.yml里每种语言下的menus.main:那些菜单项指向/docs/tutorial、/blog/release这些已不存在的路径。content/_index.md是首页,保留它,把正文换成你的。 -
清数据
data/下三组数据分别供首页、Landing 页与发布页使用。首页数据保留后修改,另外两组用不到就删除。data/home/en.yaml与data/home/zh.yaml决定首页有哪些分区,逐项含义见首页与落地页。删除整个data/home/也能构建,首页退回为普通内容页。 -
换身份
最后把
hugo.yml里的站名、params.productionURL、params.github_repo与品牌参数换成你的,替换static/下的 logo 与 favicon,删掉services.googleAnalytics、params.comments与params.version*这些 OINK 专用配置。逐条清单见十分钟上手第 3 步。
主题的位置
主题以 Hugo Module 的形式引用,两处配置指向它:
hugo.yml 声明使用哪个主题,go.mod 固定用它的哪一版,go.sum 记录该版本的校验和。三个文件都要提交。主题源码不进你的仓库:Hugo 把它下载到 Go 的模块缓存,hugo mod graph 显示实际解析结果。
升级到最新版:
固定到某一个版本:
两条命令都会改写 go.mod 与 go.sum。生产站点固定到发布标签,不要跟随 main。升级前后检查什么、如何回滚,见版本升级。
站点覆盖
layouts/ 下的文件按 Hugo 的模板查找顺序盖过主题里的同名文件。本站只放了一类:
layouts/_shortcodes/*.html:站点自己的 shortcode。产品文档需要带业务语义的 shortcode 时也放这里。
标题自链锚点由主题的 _markup/render-heading.html 提供,站点不需要自己建这个钩子。
要改外壳(侧栏、页脚、页尾)时,覆盖最窄的那个 partial,不要整份复制 baseof.html:复制之后每次主题升级都要手工合并。
验证
每删一步运行一次构建,报错能定位到刚删除的内容:
删除完成后,这几条应当成立:
- 构建以
Total in …结束,没有WARN/ERROR - 顶栏菜单没有指向已删目录的死链
- 标题右侧仍然有自链锚点(主题自带的标题渲染钩子,站点不需要覆盖)
git status里没有public/、resources/
相关
- 十分钟上手 — 克隆、改配置、部署的完整流程
- 从零建站与其它安装方式 — 从空目录搭建,不做删减
- 组织内容 —
content/的目录结构怎么变成侧栏 - 配置总览 —
hugo.yml每个键的含义与默认值 - 版本升级 — 升级主题模块与迁移工具
2 - 从零建站与其它安装方式
本页从空目录搭建一个最小 OINK 站点:十几行 hugo.yml 加一条 hugo mod get,得到一个可预览的单语站点。代价是首页、示例内容与可参照的组件用法都要自己写。
已有 Hugo 站点时不需要脚手架:装上主题模块,再补三项 goldmark 前置配置(见写 hugo.yml),正文不用重写。已有 Docsy 站点见版本升级。
后半部分是四种安装方式的取舍:Hugo Module、Git submodule、离线归档、固定版本克隆。
从空目录到第一页
-
建骨架并获取主题
hugo mod init后面跟的是你自己站点的模块路径,通常就是仓库地址。hugo mod get会写出go.mod与go.sum,两个都要提交。最新版本号在 GitHub Releases;本页出现的
v0.6.0是本站当前固定的版本。生产站点固定到发布标签,不要跟随main:@latest是一次性解析动作,不是版本策略。 -
写
hugo.yml把
hugo new site生成的hugo.yaml改名为hugo.yml(两个后缀 Hugo 都接受,本文统一用后者),内容替换为下面这份,可直接构建:hugo.yml五段分别管什么:
段 管什么 少了会怎样 顶层 + languages站名、域名、语言与顶栏菜单 baseURL不对,线上所有绝对链接指错markup.goldmark三项组件前置 属性行变成正文里的一行 {.steps}params搜索、仓库链接、外壳开关 交互功能默认关闭,主题不替站点决定 outputs每页的 .md、llms.txt、打印页页面菜单里没有「复制 Markdown」,也没有打印视图 module引用主题、声明 Hugo 下限 构建时找不到主题 -
写第一页
content/下的每个一级目录是一个分区,目录结构就是侧栏结构。文档分区至少要有一个_index.md:content/docs/_index.mdcontent/docs/install.md标题写显式
{#id}:后续加译文时两种语言的锚点才能对应。页面写法见编写页面。 -
预览
打开 http://localhost:1313/,侧栏里有 Docs → Install。修改文件是毫秒级热重载。
其它安装方式
上面用的是 Hugo Module。另外三种方式面向特定约束:网络隔离、平台要求构建输入包含完整主题树、组织内部需要评审主题副本。除 hugo mod vendor 之外,它们都不建立 Go 模块,站点用 theme: oink 而不是 module.imports 引用主题;共同的代价是版本解析与完整性校验由你自己负责。
Hugo Module(推荐)
唯一能让 Hugo 自己解析版本、校验 checksum、并在 go.sum 里留下审计记录的方式。hugo mod graph 看实际解析结果,hugo mod get -u 升级。需要本机有 Go。
Git submodule
在站点仓库里记录准确的主题 commit:
CI 必须在运行 Hugo 之前初始化 submodule,否则 themes/oink 是空目录:
离线归档
网络隔离环境使用。两条路径,都先在联网机器上准备,再整体搬入。
用 hugo mod vendor:把已解析的主题源码固化进站点目录,之后构建既不联网也不需要 Go。
_vendor/ 存在时 Hugo 优先使用它(hugo mod graph 输出 +vendor),hugo.yml 里的 module.imports 保持不变。这一步需要 Go,之后的构建不需要。升级主题要回到联网环境重新执行 hugo mod get 与 hugo mod vendor。
_vendor/ 只收主题挂载出来的目录(assets data i18n layouts static)以及 hugo.yaml 与 theme.toml,不含 LICENSE、NOTICE 与 VENDOR.json。要对外分发这份归档,把这三个文件从主题仓库一并取来。
用 tag 源码归档:不建 Go 模块,直接把某个版本的主题解压到 themes/oink/。
主题仓库的根目录就是模块根目录,解压出来直接是 layouts/、assets/、i18n/、static/ 这一层,不需要再进入下一级。重新分发时必须保留 LICENSE、NOTICE 与 VENDOR.json。最后一个记录了每个第三方运行时的版本、来源、许可证路径与 SHA-256,是离线审计的依据。
跨机器传输时,在联网侧从不可变标签生成归档与校验值:
把归档与 .sha256 一起传入隔离环境,先校验再解压:
这样得到的归档是自建产物,不是项目发行物。某个标签的发行页面是否附带归档与校验文件按发布而定,使用公开附件时独立验证其校验值。
断网构建之前确认归档内容完整,这十一项都要在:
themes/oink/
- oink/
- go.mod模块路径声明,Hugo Module 方式解析用
- hugo.yaml主题默认参数与 Hugo 版本下限
- theme.toml主题元数据,theme: oink 方式需要
- LICENSEApache-2.0
- NOTICE上游署名,再分发时必须保留
- VENDOR.json第三方运行时清单:版本、来源、许可证路径、SHA-256
- assets/SCSS、JS 与随主题分发的第三方运行时
- layouts/模板、partial、shortcode、render hook
- static/字体文件,原样发布
- i18n/32 份界面语言文件
- data/页尾出处行用的 SPDX 许可证表
固定版本克隆
托管平台要求构建输入包含完整主题树时用:
与 submodule 的区别是主题文件直接进入你的仓库历史,没有 .gitmodules 这层间接。记录最终解析出的 commit 与恢复流程。
四种方式对比
| 方式 | 需要 Go | 版本可审计 | 主题源码进你的仓库 | 适用 |
|---|---|---|---|---|
| Hugo Module | 是 | go.sum 自动校验 |
否 | 默认推荐 |
| Git submodule | 否 | 仓库记录 commit | 以引用形式 | 需要主题源码在库内 |
| 离线归档 | 否 | 手工核对 checksum | 是 | 网络隔离 |
| 固定版本克隆 | 否 | 需自行记录 | 是 | 平台要求完整树 |
Bootstrap、Font Awesome、字体、搜索与图表运行时全部随主题分发。站点不需要 node_modules、PostCSS、RTLCSS,也不需要 CDN。为 Docsy 站点安装 npm 依赖的教程属于上游 Docsy 的流程,不适用于 OINK。
用本地主题 checkout 开发
同时修改主题与站点时才需要这一节。把两个仓库克隆为同级目录:
用环境变量 HUGO_MODULE_REPLACEMENTS 把模块临时替换为本地 checkout,go.mod 不变:
文档站仓库的 Makefile 就是这几条命令的别名,make dev 与 make check 要求主题 checkout 在同级目录 ../oink:
Go workspace(go work init + HUGO_MODULE_WORKSPACE=go.work)是等价的另一种做法。两种做法都只作用于本机:CI 与生产构建用的是 go.mod 里的版本,go.work 不要提交。
验证
构建以 Total in … 结束、没有 WARN / ERROR 即通过。再确认:
/docs/打得开,侧栏里有你写的页面- 顶栏有搜索框,搜得到刚写的标题
- 深浅色切换按钮在,切换后代码块配色跟着变(说明
markup.highlight.noClasses: false生效) git status里有go.mod与go.sum,没有public/、resources/