Hugo 静态网站构建实战手册

资源管道

使用 Hugo Pipes 处理 Sass、CSS、JavaScript、图片、指纹哈希和响应式资源

资源管道

Hugo Pipes 是 Hugo 内置的资源处理系统。它可以在构建时处理 CSS、Sass、JavaScript、图片、指纹哈希、压缩和缓存,让静态站也拥有接近前端工程化的资源管理能力。

简单判断:

  • 需要处理、压缩、打包、加指纹的资源放 assets/
  • 不需要处理、只想原样复制的资源放 static/
  • 只属于某篇文章的图片和附件放 Page Bundle

assets 与 static 的区别

目录处理方式引用方式适合
assets/经过 Hugo Pipes 处理resources.GetSass、JS、可处理图片
static/原样复制到 public/直接写 URLfavicon、PDF、验证文件
Page Bundle作为页面资源处理.Resources.GetMatch文章封面、附件、图集

CSS 处理

目录示例:

assets/
└── css/
    └── main.css

模板中引用:

{{ with resources.Get "css/main.css" }}
  {{ $css := . | minify | fingerprint }}
  <link rel="stylesheet" href="{{ $css.RelPermalink }}" integrity="{{ $css.Data.Integrity }}" crossorigin="anonymous">
{{ end }}

fingerprint 会给文件名加内容哈希,适合长期缓存:

/css/main.min.abc123.css

Sass/SCSS 处理

目录示例:

assets/
└── scss/
    ├── main.scss
    ├── _variables.scss
    └── _layout.scss

main.scss

@use "variables";
@use "layout";

body {
  color: variables.$text-color;
}

模板中编译:

{{ $opts := dict "targetPath" "css/main.css" "outputStyle" "compressed" }}
{{ with resources.Get "scss/main.scss" }}
  {{ $css := . | css.Sass $opts | fingerprint }}
  <link rel="stylesheet" href="{{ $css.RelPermalink }}" integrity="{{ $css.Data.Integrity }}" crossorigin="anonymous">
{{ end }}

注意:

  • Hugo Extended 和 Extended/deploy 内置 LibSass
  • Sass 官方已弃用 LibSass,新语法建议使用 Dart Sass
  • Dart Sass 需要在本地和 CI/CD 环境中安装
  • 如果主题文档要求 Dart Sass,不要只安装 Hugo Extended

PostCSS

如果主题使用 Tailwind CSS、Autoprefixer 或其他 PostCSS 插件,需要 Node.js 环境。

安装依赖:

npm init -y
npm install -D postcss postcss-cli autoprefixer

postcss.config.js

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

模板中处理:

{{ $css := resources.Get "css/main.css" | postCSS | minify | fingerprint }}
<link rel="stylesheet" href="{{ $css.RelPermalink }}" integrity="{{ $css.Data.Integrity }}" crossorigin="anonymous">

CI 构建时要记得:

npm ci
hugo --minify

JavaScript 打包

Hugo 的 js.Build 基于 esbuild,可用于打包、转译、tree shaking、minify 和 source map。

目录示例:

assets/
└── js/
    ├── main.js
    └── search.js

模板中引用:

{{ $opts := dict "targetPath" "js/main.js" "minify" hugo.IsProduction }}
{{ with resources.Get "js/main.js" }}
  {{ $js := . | js.Build $opts | fingerprint }}
  <script src="{{ $js.RelPermalink }}" integrity="{{ $js.Data.Integrity }}" crossorigin="anonymous" defer></script>
{{ end }}

开发环境保留 source map:

{{ $opts := dict
  "targetPath" "js/main.js"
  "minify" hugo.IsProduction
  "sourceMap" (cond hugo.IsProduction "" "inline")
}}

TypeScript 入口也可以处理:

assets/js/main.ts
{{ $js := resources.Get "js/main.ts" | js.Build (dict "targetPath" "js/main.js") }}

图片处理

Hugo 可以处理 Page Bundle、assets/ 和远程资源中的图片。常见方法:

方法作用示例
.Resize按宽高缩放Resize "800x"
.Fit等比缩放到指定框内Fit "800x600"
.Fill裁剪填充指定尺寸Fill "1200x630"
.Crop裁剪Crop "600x400"
.Filter应用滤镜images.GaussianBlur 6

文章 Page Bundle:

content/posts/hugo-images/
├── index.md
└── cover.jpg

模板:

{{ with .Resources.GetMatch "cover.*" }}
  {{ $cover := .Fill "1200x630 webp q80" }}
  <img src="{{ $cover.RelPermalink }}" width="{{ $cover.Width }}" height="{{ $cover.Height }}" alt="{{ $.Title }}">
{{ end }}

webp q80 表示输出 WebP,质量 80。

响应式图片

可以生成 srcset

{{ with .Resources.GetMatch "cover.*" }}
  {{ $small := .Resize "480x webp q75" }}
  {{ $medium := .Resize "800x webp q75" }}
  {{ $large := .Resize "1200x webp q75" }}
  <img
    src="{{ $medium.RelPermalink }}"
    srcset="{{ $small.RelPermalink }} 480w, {{ $medium.RelPermalink }} 800w, {{ $large.RelPermalink }} 1200w"
    sizes="(max-width: 768px) 100vw, 800px"
    width="{{ $medium.Width }}"
    height="{{ $medium.Height }}"
    alt="{{ $.Title }}"
    loading="lazy">
{{ end }}

建议写入 widthheight,减少页面布局抖动。

远程资源

可以读取远程图片或数据:

{{ with resources.GetRemote "https://example.org/image.jpg" }}
  {{ $img := .Resize "800x webp" }}
  <img src="{{ $img.RelPermalink }}" alt="">
{{ end }}

远程资源会增加构建时对网络的依赖。生产环境更建议把关键资源放在仓库或稳定 CDN 中。

资源合并

多个 CSS 合并:

{{ $base := resources.Get "css/base.css" }}
{{ $syntax := resources.Get "css/syntax.css" }}
{{ $css := slice $base $syntax | resources.Concat "css/bundle.css" | minify | fingerprint }}
<link rel="stylesheet" href="{{ $css.RelPermalink }}" integrity="{{ $css.Data.Integrity }}" crossorigin="anonymous">

多个 JS 合并:

{{ $a := resources.Get "js/a.js" }}
{{ $b := resources.Get "js/b.js" }}
{{ $js := slice $a $b | resources.Concat "js/bundle.js" | minify | fingerprint }}
<script src="{{ $js.RelPermalink }}" integrity="{{ $js.Data.Integrity }}" crossorigin="anonymous" defer></script>

如果 JS 之间有模块依赖,优先使用 js.Build

缓存与 fingerprint

生产环境推荐:

{{ $css := resources.Get "css/main.css" | minify | fingerprint "sha384" }}
<link rel="stylesheet" href="{{ $css.RelPermalink }}" integrity="{{ $css.Data.Integrity }}" crossorigin="anonymous">

这样浏览器可以长期缓存文件;内容变化后文件名也会变化。

服务器或 CDN 可设置:

Cache-Control: public, max-age=31536000, immutable

没有 fingerprint 的 HTML 不要设置过长缓存。

构建模式判断

模板中可以用:

{{ if hugo.IsProduction }}
  {{/* 生产环境 */}}
{{ else }}
  {{/* 开发环境 */}}
{{ end }}

常见用法:

{{ $opts := dict "minify" hugo.IsProduction }}

生产构建:

HUGO_ENVIRONMENT=production hugo --minify

Windows PowerShell:

$env:HUGO_ENVIRONMENT = "production"
hugo --minify

资源缓存目录

图片处理和资源构建结果通常缓存到 resources/。缓存能提升二次构建速度。

常见 .gitignore

/public/
/resources/
/.hugo_build.lock

如果 CI 每次重新构建,可使用平台缓存能力缓存 resources/,但不是必须。

常见问题

Q: resources.Get 返回空

A: 检查路径是否相对于 assets/。例如文件是 assets/css/main.css,模板里写 resources.Get "css/main.css"

Q: Sass 构建失败

A: 检查是否安装 Hugo Extended。如果主题使用 Sass 新语法,再检查是否安装 Dart Sass。

Q: PostCSS 本地正常,线上失败

A: 线上没有执行 npm ci,或 Node 版本不一致。部署平台需要配置 Node.js 与安装命令。

Q: 图片没有被处理

A: 确认图片是 Page Resource 或放在 assets/ 中。static/ 中的图片不会被 Hugo Pipes 处理。

下一步

继续阅读 Hugo Modules,学习如何用模块管理主题、资源和大型站点结构。

评论

0%