跳到主要内容

Hugo Modules

Hugo Modules 是 Hugo 的依赖管理系统,基于 Go Modules 构建。它提供了一种现代化、标准化的方式来管理主题、组件和其他依赖项。

什么是 Hugo Modules?

Hugo Modules 让你能够:

  • 导入和使用远程主题,无需手动下载
  • 管理主题和组件的版本
  • 共享内容、模板、资源和配置
  • 组合多个模块构建复杂的站点

相比传统的 Git 子模块方式,Hugo Modules 提供了更好的版本控制和依赖解析能力。

前置条件

使用 Hugo Modules 需要安装 Go:

Windows

# 使用 Chocolatey
choco install golang

# 或使用 Scoop
scoop install go

macOS

brew install go

Linux

golang.org 下载安装包,或使用包管理器:

# Ubuntu/Debian
sudo apt install golang

# Fedora
sudo dnf install golang

验证安装:

go version

初始化模块

在项目根目录运行以下命令初始化模块:

# 自动推断模块路径
hugo mod init

# 或手动指定模块路径
hugo mod init github.com/yourname/myblog

这会创建一个 go.mod 文件:

module github.com/yourname/myblog

go 1.21

导入主题

使用配置文件导入

hugo.toml 中添加模块导入:

[module]
[[module.imports]]
path = 'github.com/theNewDynamic/gohugo-theme-ananke'

YAML 格式:

module:
imports:
- path: github.com/theNewDynamic/gohugo-theme-ananke

首次下载

添加导入配置后,运行任意 Hugo 命令会自动下载模块:

hugo server
# 或
hugo

模块会下载到 Hugo 的缓存目录(通常是 $HOME/go/pkg/mod/)。

模块命令

更新模块

# 更新所有模块到最新版本
hugo mod get -u

# 递归更新所有模块
hugo mod get -u ./...

# 更新特定模块
hugo mod get -u github.com/theNewDynamic/gohugo-theme-ananke

# 更新到特定版本
hugo mod get github.com/theNewDynamic/[email protected]

# 更新到最新提交
hugo mod get github.com/theNewDynamic/gohugo-theme-ananke@latest

查看依赖图

hugo mod graph

输出示例:

github.com/yourname/myblog github.com/theNewDynamic/[email protected]
github.com/yourname/myblog github.com/gohugoio/[email protected]
github.com/theNewDynamic/[email protected] github.com/gohugoio/[email protected]

清理模块缓存

# 清理整个模块缓存
hugo mod clean

# 清理项目依赖
hugo mod tidy

Vendor 模块

将依赖复制到项目的 _vendor 目录:

hugo mod vendor

这会将所有模块复制到本地,适合以下场景:

  • 需要离线构建
  • 想要锁定依赖版本
  • CI/CD 环境不支持网络访问

注意:Vendor 目录中的模块不会自动更新,需要手动运行 hugo mod vendor

模块配置

基本配置

[module]
# Hugo 版本要求
[module.hugoVersion]
extended = true # 需要 Hugo Extended
min = '0.100.0' # 最低版本
max = '' # 最高版本(空表示不限制)

# 导入的模块
[[module.imports]]
path = 'github.com/theNewDynamic/gohugo-theme-ananke'
disable = false # 是否禁用此模块

[[module.imports]]
path = 'github.com/yourname/hugo-component-gallery'

模块挂载点

挂载点控制模块中的目录如何映射到项目目录:

[module]
[[module.imports]]
path = 'github.com/theNewDynamic/gohugo-theme-ananke'

# 自定义挂载点
[[module.imports.mounts]]
source = 'static' # 模块中的目录
target = 'static' # 项目中的目标位置

[[module.imports.mounts]]
source = 'layouts'
target = 'layouts'

[[module.imports.mounts]]
source = 'content'
target = 'content'

项目级挂载配置

也可以在项目级别配置挂载点:

[module]
[[module.mounts]]
source = 'content'
target = 'content'

[[module.mounts]]
source = 'static'
target = 'static'

[[module.mounts]]
source = 'layouts'
target = 'layouts'

[[module.mounts]]
source = 'assets'
target = 'assets'

# 多语言配置
[[module.mounts]]
source = 'content/en'
target = 'content'
lang = 'en'

[[module.mounts]]
source = 'content/zh'
target = 'content'
lang = 'zh'

版本配置

Hugo 0.150 引入了直接在配置文件中指定模块版本的功能。这让你可以在 hugo.toml 中直接控制导入模块的版本,而不需要修改 go.mod 文件。

基本用法

[module]
[[module.imports]]
path = 'github.com/theNewDynamic/gohugo-theme-ananke'
version = 'v2.8.1'

使用分支或标签

[module]
[[module.imports]]
path = 'github.com/user/my-theme'
version = 'main' # 使用主分支最新代码

[[module.imports]]
path = 'github.com/user/another-theme'
version = 'develop' # 使用开发分支

[[module.imports]]
path = 'github.com/user/component'
version = 'v1.0.0' # 使用特定标签

实际应用场景:多版本文档站点

一个常见的用例是将同一内容的不同版本挂载到同一个站点中:

[module]
# 当前版本
[[module.imports]]
path = 'github.com/myorg/docs'
version = 'main'

# 旧版本 v2.x
[[module.imports]]
path = 'github.com/myorg/docs'
version = 'v2.0.0'
[[module.imports.mounts]]
source = 'content'
target = 'content/v2'

# 旧版本 v1.x
[[module.imports]]
path = 'github.com/myorg/docs'
version = 'v1.0.0'
[[module.imports.mounts]]
source = 'content'
target = 'content/v1'

这样可以在同一个站点中提供多个版本的文档,用户可以切换查看不同版本的内容。

版本配置优先级

配置文件中的 version 设置会覆盖 go.mod 中的版本要求。这对于开发测试特别有用,可以快速切换到不同版本进行测试。

替换指令

在开发过程中,可以用本地目录替换远程模块:

[module]
[[module.imports]]
path = 'github.com/theNewDynamic/gohugo-theme-ananke'

# 使用 replacements 替换
replacements = 'github.com/theNewDynamic/gohugo-theme-ananke -> /path/to/local/ananke'

或者直接修改 go.mod 文件:

replace github.com/theNewDynamic/gohugo-theme-ananke => /path/to/local/ananke

工作区(Workspace)

工作区功能让你可以同时开发多个模块,适合主题开发者。

创建工作区

创建 hugo.work 文件:

go 1.21

use .
use ../gohugo-theme-ananke

use 指令指定要包含的模块路径。

启用工作区

通过环境变量启用工作区:

HUGO_MODULE_WORKSPACE=hugo.work hugo server

或使用命令行参数:

hugo server --config hugo.toml,hugo.work

启用工作区后,Hugo 会监听所有模块目录的变化,本地修改会立即反映到开发服务器中。

实际应用场景

导入主题

最常见用法是导入主题:

[module]
[[module.imports]]
path = 'github.com/theNewDynamic/gohugo-theme-ananke'

导入组件

模块可以是主题的一部分:

[module]
[[module.imports]]
path = 'github.com/yourname/hugo-component-analytics'

共享内容

多个站点可以共享内容:

[module]
[[module.imports]]
path = 'github.com/company/shared-content'

[[module.imports.mounts]]
source = 'content'
target = 'content'

导入短代码集合

[module]
[[module.imports]]
path = 'github.com/gohugoio/hugo-mod-jslibs'

模块 vs Git 子模块

特性Hugo ModulesGit Submodules
版本管理灵活(语义化版本)限于 commit/tag
依赖解析自动手动
多模块支持原生需要多个子模块
本地开发工作区支持需要修改配置
构建速度较快较慢
学习曲线中等简单
需要 Go

目录结构

使用模块后的项目结构:

myblog/
├── go.mod # 模块定义
├── go.sum # 依赖校验(自动生成)
├── hugo.toml # 站点配置
├── content/
├── layouts/
├── assets/
├── static/
├── themes/ # 可选,用于本地主题开发
├── _vendor/ # vendor 后的依赖(可选)
└── resources/ # Hugo 缓存

缓存配置

配置模块缓存位置和行为:

[caches]
[caches.modules]
dir = ':cacheDir/modules'
maxAge = -1 # 永不过期

:cacheDir 的默认位置:

  • Linux/Unix: $HOME/.cache/hugo_cache/
  • macOS: $HOME/Library/Caches/hugo_cache/
  • Windows: %LOCALAPPDATA%\hugo_cache\

常见问题

模块下载失败

检查网络连接和 Go 模块代理设置:

# 设置代理(中国大陆用户)
go env -w GOPROXY=https://goproxy.cn,direct

# 或使用阿里云镜像
go env -w GOPROXY=https://mirrors.aliyun.com/goproxy/,direct

版本冲突

查看依赖图分析冲突:

hugo mod graph

使用特定版本解决冲突:

hugo mod get module/[email protected]

私有模块

对于私有仓库,配置 Git 凭据:

# 配置 Git 使用 SSH
git config --global url."[email protected]:".insteadOf "https://github.com/"

# 设置私有模块
go env -w GOPRIVATE=github.com/yourcompany/*

清理后重新下载

# 清理缓存
hugo mod clean

# 重新下载
hugo mod get

命令速查

命令说明
hugo mod init初始化模块
hugo mod get -u更新所有模块
hugo mod get [email protected]更新到特定版本
hugo mod graph显示依赖图
hugo mod tidy清理未使用的依赖
hugo mod clean清理模块缓存
hugo mod vendor将依赖复制到本地

Node.js 依赖管理

Hugo 可以管理 Node.js 依赖,这对于使用 PostCSS、Tailwind CSS 等工具的项目很有用。

自动安装

Hugo 可以自动检测并安装 package.json 中定义的依赖:

# Hugo 会自动运行 npm install
hugo

# 或者显式安装
hugo mod npm pack

package.json 配置

在项目根目录创建 package.json

{
"name": "my-hugo-site",
"version": "1.0.0",
"devDependencies": {
"postcss": "^8.4.21",
"postcss-cli": "^10.1.0",
"autoprefixer": "^10.4.14",
"tailwindcss": "^3.3.0"
}
}

Hugo 配置

hugo.toml 中启用 Node.js 依赖管理:

[module]
[[module.imports]]
path = 'github.com/theNewDynamic/gohugo-theme-ananke'

[hugoVersion]
extended = true
min = "0.100.0"

# 构建时安装 Node.js 依赖
[build]
writeStats = true

模块和 Node.js 依赖

Hugo Modules 可以包含 package.json 文件,Hugo 会自动合并所有模块的依赖:

my-site/
├── package.json # 项目依赖
├── go.mod
└── themes/
└── my-theme/
├── package.json # 主题依赖
└── ...

Hugo 会合并这两个 package.json 文件中的依赖,然后安装。

使用 npm 包

安装完成后,可以在模板中使用这些包:

PostCSS 配置

创建 postcss.config.js

module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
}
}

在模板中使用

{{ $css := resources.Get "css/main.css" | postCSS | minify | fingerprint }}
<link rel="stylesheet" href="{{ $css.Permalink }}">

Node.js 版本管理

确保团队使用相同的 Node.js 版本,创建 .nvmrc 文件:

18.17.0

或创建 .node-version 文件:

18.17.0

团队成员可以使用 nvmfnm 自动切换到正确的 Node.js 版本。

npm 命令集成

可以在 Hugo 的构建过程中集成自定义 npm 脚本:

package.json

{
"scripts": {
"build:css": "tailwindcss -i ./assets/css/input.css -o ./assets/css/output.css",
"watch:css": "tailwindcss -i ./assets/css/input.css -o ./assets/css/output.css --watch"
}
}

然后运行:

# 开发模式
npm run watch:css & hugo server

# 生产构建
npm run build:css && hugo --minify

故障排除

依赖安装失败

检查网络连接和 npm 镜像设置:

# 设置镜像
npm config set registry https://registry.npmmirror.com

版本冲突

确保 package.jsonpackage-lock.json 同步:

rm -rf node_modules package-lock.json
npm install

缓存问题

清理 npm 缓存:

npm cache clean --force
hugo mod clean

最佳实践

  1. 版本锁定:生产环境使用特定版本号,避免自动更新带来的意外变化
  2. 使用 vendor:对于重要项目,使用 hugo mod vendor 确保可重复构建
  3. 定期更新:定期运行 hugo mod get -u 并测试,保持依赖最新
  4. 本地开发:使用工作区或 replace 指令进行本地主题开发
  5. 版本要求:在 hugoVersion 中明确指定 Hugo 版本要求

小结

Hugo Modules 是管理 Hugo 项目依赖的现代方式,主要优势包括:

  • 标准化的版本管理
  • 灵活的模块组合
  • 强大的本地开发支持
  • 与 Go 生态集成

虽然相比 Git 子模块有一定学习成本,但带来的便利性和灵活性使其成为大型项目的首选方案。