页面资源管理:图片、附件、音频、代码块等

通过页面包(Page Bundle)方式将图片、音频等资源与内容放在同一目录,方便引用和迁移。利用 .Resources 访问这些文件,并结合 resources.Get 等函数进行按需处理,使资源管理更有条理。

阅读本节后,你将理解页面资源管理:图片、附件、音频、代码块等在构建流程中的角色,并掌握常见配置方式。 讲解如何借助 resources 管理器处理图片派生和指纹,使引用路径始终稳定。 还会分享调试和优化经验,帮助在复杂场景下保持文档与代码的可维护性。

页面包:内容与资源的结合

Hugo 的页面包(Page Bundle)是一种将内容文件(Markdown)与其相关资源(图片、PDF、附件等)组织在一起的方式。这种方式让内容和资源内聚,便于管理和迁移。

页面包主要分为两种类型:

叶子包 (Leaf Bundle)

叶子包是一个包含 index.md 文件的目录。该目录下的所有其他文件都被视为与这个页面关联的页面资源,它们只能通过这个页面进行访问。

content/
└── blog/
    └── my-awesome-post/
        ├── index.md         # 页面内容
        ├── cover.jpg        # 页面资源
        ├── chart.png        # 页面资源
        └── data.json        # 页面资源
  • 适用场景:单个博客文章、产品介绍页等独立的、有自己专属资源的内容页面。
  • URLmy-awesome-post 目录名决定了页面的 URL,例如 /blog/my-awesome-post/

分支包 (Branch Bundle)

分支包是一个包含 _index.md 文件的目录。它本身是一个列表页面,同时也可以有自己的页面资源。其下的子目录可以是叶子包或其他分支包。

content/
└── gallery/
    ├── _index.md        # gallery 列表页内容
    ├── header.jpg       # gallery 列表页的资源
    ├── nature/          # 子内容区(分支包)
    │   ├── _index.md
    │   └── featured.png
    └── city/            # 子内容区(叶子包)
        ├── index.md
        └── new-york.jpg
  • 适用场景:内容区的概览页面,如博客列表页、相册主页。
  • URLgallery 目录名决定了其 URL,例如 /gallery/

访问页面资源

一旦你将资源组织在页面包中,就可以在模板中通过页面的 .Resources 变量来访问它们。.Resources 是一个包含了所有该页面资源的集合。

{{/* 在 single.html 模板中 */}}

<h1>{{ .Title }}</h1>
<div>{{ .Content }}</div>

<h2>本页资源列表:</h2>
<ul>
  {{ range .Resources }}
    <li><a href="{{ .RelPermalink }}">{{ .Name }}</a> ({{ .MediaType }})</li>
  {{ end }}
</ul>
  • .Resources:一个可遍历的集合,包含页面包内除 index.md_index.md 外的所有文件。
  • .RelPermalink:资源的相对链接。
  • .Name:资源的文件名。
  • .MediaType:资源的媒体类型,如 image/jpeg

资源类型与筛选

通常我们不希望列出所有资源,而是需要筛选出特定类型或名称的资源。.Resources 提供了多种筛选方法。

按资源类型筛选

使用 .Resources.ByType 方法可以方便地获取特定类型的资源,如所有图片。

<h3>本页所有图片:</h3>
{{ range .Resources.ByType "image" }}
  <img src="{{ .RelPermalink }}" alt="{{ .Name }}" />
{{ end }}

按文件名匹配

使用 .Resources.Match 方法可以通过 Glob 模式匹配文件名。

{{/* 获取所有 .jpg 文件 */}}
{{ range .Resources.Match "*.jpg" }}
  <img src="{{ .RelPermalink }}" alt="{{ .Name }}">
{{ end }}

{{/* 获取所有以 "cover" 开头的文件 */}}
{{ $cover := .Resources.Match "cover.*" }}

图片处理

页面资源最强大的功能之一是图片处理。你可以对获取到的图片资源进行动态的裁剪、缩放、格式转换等操作。

假设 my-awesome-post 页面包中有一张 cover.jpg

{{ $original := .Resources.GetMatch "cover.jpg" }}

{{ if $original }}
  {{/* 缩放图片到 800px 宽,并保持宽高比 */}}
  {{ $thumb := $original.Resize "800x" }}
  <img src="{{ $thumb.RelPermalink }}" width="{{ $thumb.Width }}" height="{{ $thumb.Height }}">

  {{/* 裁剪图片为 400x400 大小,并转换为 webp 格式 */}}
  {{ $cropped := $original.Fill "400x400" }}
  {{ $webp := $cropped.Process "webp" }}
  <img src="{{ $webp.RelPermalink }}">
{{ end }}
  • .Resources.GetMatch:获取单个匹配的资源。
  • .Resize.Fill:图片处理函数。
  • .Process:进行格式转换等处理。
  • 指纹保护:所有经过处理的资源,Hugo 都会为其生成带哈希指纹的文件名(如 cover_hu345f.jpg),以实现高效的浏览器缓存控制。你无需关心文件名,只需使用返回对象的 .RelPermalink 即可。

其他资源的处理

同样的方式也适用于非图片资源。例如,你可以列出所有 PDF 附件供用户下载。

<h3>附件下载:</h3>
<ul>
  {{ range .Resources.Match "*.pdf" }}
    <li>
      <a href="{{ .RelPermalink }}" download>{{ .Title }}</a> ({{ .MediaType }})
    </li>
  {{ end }}
</ul>
  • .Title:你可以在资源的 Front Matter 中为其指定一个更友好的标题。只需在页面包中创建一个与资源同名的 .md 文件即可。

    my-awesome-post/
    ├── my-document.pdf
    └── my-document.pdf.md
    

    my-document.pdf.md 文件内容:

    ---
    title: "我的年度报告"
    ---
    

全局资源管理

对于需要在整个网站多处使用的资源(如 logo、全局 CSS/JS),应将它们放在 assets 目录下,并通过 resources.Get 进行调用和处理。

{{ $logo := resources.Get "images/logo.png" }}
{{ $resizedLogo := $logo.Resize "200x" }}
<img src="{{ $resizedLogo.RelPermalink }}">

最佳实践

  • 优先使用页面包:对于与特定内容紧密相关的资源,应优先使用页面包进行管理。这使得内容更具可移植性。
  • 利用图片处理:充分利用 Hugo Pipes 的图片处理能力,为不同设备和场景生成最优化的图片版本,提升网站性能。
  • 为资源添加元数据:通过创建同名的 .md 文件,为资源(特别是文档和附件)提供描述性的 title 和其他参数。
  • 区分 assetsstatic:需要 Hugo 处理的资源(如 SCSS、需要优化的图片)放入 assets;无需处理、直接复制的资源(如 robots.txt、字体文件)放入 static

通过这套强大的资源管理系统,你可以构建出结构清晰、易于维护且性能卓越的 Hugo 网站。