ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Hugo 页面资源(Page Resources)完全指南:`PAGE.Resources` 方法与 `ByType`、`Get`、`GetMatch`、`Match`、`Mount` 实战解析

Hugo 页面资源(Page Resources)完全指南:`PAGE.Resources` 方法与 `ByType`、`Get`、`GetMatch`、`Match`、`Mount` 实战解析 Hugo 页面资源Page Resources完全指南PAGE.Resources方法与ByType、Get、GetMatch、Match、Mount实战解析【免费下载链接】hugoThe world’s fastest framework for building websites.项目地址: https://gitcode.com/gh_mirrors/hu/hugo本文是 Hugo 静态站点框架当前仓库中页面资源 API 的深度技术指南围绕Page对象上的Resources方法展开覆盖其返回类型、ByType/Get/GetMatch/Match/Mount五个核心子方法的用法与底层实现、glob 模式匹配规则、front matter 中的resources元数据配置以及多语言场景下共享资源的构建行为。读完本文你将能在 Hugo 模板中熟练获取、筛选、定位与重映射页面资源并理解资源查找的内部原理。什么是页面资源Page Resources在 Hugo 中页面资源page resource是指位于页面 bundle 目录内的文件。所谓 page bundle是指以index.md叶子 bundle或_index.md分支 bundle为根的目录例如content/ └── post └── first-post ├── images │ ├── a.jpg │ ├── b.jpg │ └── c.jpg ├── index.md (bundle 根) ├── latest.html ├── manual.json ├── notice.md ├── office.mp3 ├── pocket.mp4 ├── rating.pdf └── safety.txt上述first-post是一个包含 10 个页面资源音频、数据、文档、图片、视频的叶子 bundle。页面资源仅对其所属页面可见——同级的second-post虽然也是 bundle但无法直接访问first-post的资源。资源类型resource type由文件扩展名推导而来常见的类型有image、text、audio、video、application以及page指 Markdown、HTML、AsciiDoc 等可渲染内容文件。需要处理全局资源或远程资源时请改用resources.ByType、resources.Get、resources.GetMatch、resources.Match等顶层函数参见 docs/content/en/functions/resources/ByType.md 等本文聚焦页面级资源。Resources方法签名与返回值Resources方法定义在Page对象上没有任何参数属性值返回类型resource.Resourcesresource.Resource的切片签名PAGE.Resources在源码中该方法最终将请求委托给站点的内容映射按需为页面创建并返回资源集合hugolib/page.go#L419-L421func (ps *pageState) Resources() resource.Resources { return ps.s.pageMap.getOrCreateResourcesForPage(ps) }resource.Resources本质上是[]Resource的别名所有查找逻辑都定义在 resources/resource/resources.go 中。拿到资源集合后你可以对它调用ByType、Get、GetMatch、Match、Mount等方法来筛选、定位和重映射。四个定位与筛选方法ByType按资源类型筛选签名与行为返回类型resource.Resources返回给定媒体类型media type对应的所有页面资源没有匹配时返回nil典型类型取值image、text、audio、video、application模板示例——渲染 bundle 内所有图片{{ range .Resources.ByType image }} img src{{ .RelPermalink }} width{{ .Width }} height{{ .Height }} alt {{ end }}底层实现resources/resource/resources.go#L103-L116会遍历全部资源逐一比较resource.ResourceType()与目标字符串func (r Resources) ByType(typ any) Resources { tpstr, err : cast.ToStringE(typ) ... for _, resource : range r { if resource.ResourceType() tpstr { filtered append(filtered, resource) } } return filtered }注意ByType是精确匹配类型名不是 glob 匹配。Get按路径或名称精确定位单个资源签名与行为返回类型resource.Resource从给定路径返回页面资源找不到时返回nil模板示例{{ with .Resources.Get images/a.jpg }} img src{{ .RelPermalink }} width{{ .Width }} height{{ .Height }} alt {{ end }}在模板中配合else分支可以优雅处理资源缺失并抛出错误写法来自 docs/content/en/content-management/page-resources.md{{ $path : images/a.jpg }} {{ with .Resources.Get $path }} img src{{ .RelPermalink }} width{{ .Width }} height{{ .Height }} alt {{ else }} {{ errorf Unable to get page resource %q $path }} {{ end }}从源码resources/resource/resources.go#L120-L162可以看到查找的关键细节查找不区分大小写strings.EqualFold路径带不带前导/均可内部会通过paths.AddLeadingSlash规范化./前缀则被视为相对当前目录优先匹配资源的Name——Name可能被 front matter 的resources元数据改写见下文“元数据”一节其次匹配规范化名称NameNormalized不含语言代码后缀。GetMatch按 glob 模式取首个匹配签名与行为返回类型resource.Resource从路径匹配给定 glob 模式的资源中返回第一个没有匹配时返回nil匹配不区分大小写模板示例{{ with .Resources.GetMatch images/*.jpg }} img src{{ .RelPermalink }} width{{ .Width }} height{{ .Height }} alt {{ end }}实现上resources/resource/resources.go#L166-L193使用hglob.GetGlob编译模式同样先按Name再按规范化名称进行g.Match返回第一个命中项。Match按 glob 模式取全部匹配签名与行为返回类型resource.Resources返回路径匹配给定 glob 模式的全部页面资源没有匹配时返回nil模板示例——渲染images子目录下所有 jpg{{ range .Resources.Match images/*.jpg }} img src{{ .RelPermalink }} width{{ .Width }} height{{ .Height }} alt {{ end }}Match与GetMatch使用同一套 glob 规则区别仅在于前者收集全部命中项而非只取第一个。关于匹配规则的完整说明见下文“glob 模式匹配”。Mount重映射资源路径Hugo 0.140.0Mount方法{{ new-in 0.140.0 /}}用于挂载并重映射资源路径返回一个resource.ResourceGetter第一个参数base基础路径被重映射的源路径第二个参数target目标路径以/开头表示绝对路径相对目标路径则允许相对另一组资源挂载例如相对某个 page bundle官方文档中的典型用法是将全局匹配到的资源挂载到当前页面上下文供需要importContext的模板函数如css.Build、JS 构建使用{{ $common : resources.Match /js/headlessui/*.* }} {{ $importContext : (slice $.Page ($common.Mount /js/headlessui .)) }}这里先把全局resources.Match到的/js/headlessui/*.*资源从基础路径/js/headlessui重映射到相对目标路径.即当前 bundle再连同$.Page一起构造成 import 上下文切片。源码实现resources/resource/resources.go#L79-L88会构造一个持有Base、Target的挂载包装器后续路径查找时先剥离Base前缀再映射到Target。关于 resource getter 的补充说明可参考 docs/content/en/quick-reference/glossary/resource-getter.md除了Resources.Mount的返回值资源切片如slice $resource1 $resource2也是常见的 resource getter。glob 模式匹配规则GetMatch与Match使用不区分大小写的 glob 模式匹配资源路径。核心规则如下完整对照表见 docs/content/en/_common/glob-patterns.md*不跨越路径分隔符/只匹配单个路径段内的字符**可以跨越多层目录若资源组织在子目录中模式必须显式写清楚层级。以images/foo/a.jpg为例路径模式是否匹配images/foo/a.jpgimages/foo/*.jpgtrueimages/foo/a.jpgimages/foo/*.*trueimages/foo/a.jpgimages/*/*.jpgtrueimages/foo/a.jpg**/*.jpgtrueimages/foo/a.jpg**trueimages/foo/a.jpg*/*.jpgfalseimages/foo/a.jpg*.jpgfalseimages/foo/a.jpg*false也就是说*.png只匹配 bundle 根目录下的 png要匹配任意层级的 png 应使用**.png要匹配images目录下的所有 png含子目录可使用images/**.png。front matter 元数据resources参数页面资源的元数据通过所属页面 front matter 中的数组参数resources管理每个数组条目包含以下键键类型说明srcstring必填。glob 模式相对于 page bundle 匹配一个或多个资源文件不区分大小写匹配到多个资源时同一元数据应用到每个资源namestring设置Name方法返回的值支持:counter占位符赋值后应使用name而非原文件路径配合Resources.Get、Resources.Match、Resources.GetMatchtitlestring设置Title方法返回的值支持:counter占位符paramsmap自定义键值对映射多个数组条目匹配同一资源时params会合并重复键以靠后的条目为准注意资源类型为page的资源其Title等取自自身 front matter。一个完整的配置示例# content/example.md 的 front matter title: Application date: 2018-01-25 resources: - src: images/sunset.jpg name: header - src: documents/photo_specs.pdf title: Photo Specifications - src: documents/guide.pdf title: Instruction Guide - src: documents/checklist.pdf title: Document Checklist - src: documents/payment.docx title: Proof of Payment - src: **.pdf name: pdf-file-:counter params: icon: pdf - src: **.docx params: icon: word效果解读sunset.jpg获得新Name为header之后可用.GetMatch header定位四个文档分别获得各自的Title所有 PDF 获得pdf图标并因:counter占位符得到pdf-file-1、pdf-file-2、pdf-file-3这样的顺序命名所有.docx文件获得word图标。合并与优先级规则对name和title首个匹配的数组条目生效后续匹配被忽略对params所有匹配条目都贡献重复键以靠后条目为准。因此应将更具体的src模式放在通配符之前以控制name与title的归属。name与title中的:counter占位符:counter是name与title中识别的特殊占位符。每个唯一的src模式分别维护name与title的独立计数器均从 1 开始计数。例如 bundle 中有photo_specs.pdf、other_specs.pdf、guide.pdf、checklist.pdf四个文件front matter 配置# content/inspections/engine/index.md title Engine inspections [[resources]] src *specs.pdf title Specification #:counter [[resources]] src **.pdf name pdf-file-:counter.pdf则Name与Title的分配结果如下资源文件NameTitlechecklist.pdfpdf-file-1.pdfchecklist.pdfguide.pdfpdf-file-2.pdfguide.pdfother_specs.pdfpdf-file-3.pdfSpecification #1photo_specs.pdfpdf-file-4.pdfSpecification #2可见两个计数器互不影响pdf-file-N计数器对全部 PDF 递增而Specification #N计数器只对匹配*specs.pdf的两个文件递增。综合实战示例以下示例均基于如下内容结构取自 docs/content/en/content-management/page-resources.mdcontent/ └── example/ ├── data/ │ └── books.json -- page resource ├── images/ │ ├── a.jpg -- page resource │ └── b.jpg -- page resource ├── snippets/ │ └── text.md -- page resource └── index.md将所有图片缩放为 300px 宽后渲染{{ range .Resources.ByType image }} {{ with .Resize 300x }} img src{{ .RelPermalink }} width{{ .Width }} height{{ .Height }} alt {{ end }} {{ end }}渲染 Markdown 代码片段资源的内容{{ with .Resources.Get snippets/text.md }} {{ .Content }} {{ end }}读取 JSON 数据文件并用transform.Unmarshal解析文件缺失时抛出明确错误{{ $path : data/books.json }} {{ with .Resources.Get $path }} {{ with . | transform.Unmarshal }} pBooks:/p ul {{ range . }} li{{ .title }}/li {{ end }} /ul {{ end }} {{ else }} {{ errorf Unable to get page resource %q $path }} {{ end }}捕获资源后即可对其调用Resource对象的各类方法RelPermalink、Width、Height、Content、Resize、Name、Title、Params等完成输出或处理。多语言项目中的共享页面资源在多语言单主机项目中Hugo默认不会在构建时复制共享页面资源而是将它们放在默认内容语言的 bundle 中以降低构建时间、存储、带宽与部署成本。该行为仅对 Markdown 内容生效其他内容格式的共享资源会被复制到每个语言的 bundle 中。例如以下配置与内容defaultContentLanguage de defaultContentLanguageInSubdir true [languages.de] label Deutsch locale de-DE weight 1 [languages.en] label English locale en-US weight 2content/ └── my-bundle/ ├── a.jpg -- 共享页面资源 ├── b.jpg -- 共享页面资源 ├── c.de.jpg ├── c.en.jpg ├── index.de.md └── index.en.md构建后共享资源只出现在德语默认语言bundle 中public/ ├── de/ │ ├── my-bundle/ │ │ ├── a.jpg -- 共享页面资源 │ │ ├── b.jpg -- 共享页面资源 │ │ ├── c.de.jpg │ │ └── index.html │ └── index.html ├── en/ │ ├── my-bundle/ │ │ ├── c.en.jpg │ │ └── index.html │ └── index.html └── index.html重要注意事项要正确解析 Markdown 中的链接与图片目标必须使用能通过Resources.Get捕获页面资源并调用其RelPermalink的链接/图片渲染钩子。Hugo 默认配置下会自动使用内嵌链接与图片渲染钩子若项目、模块或主题自定义了钩子则会使用自定义版本也可通过配置让 Hugoalways始终、fallback回退或never从不使用内嵌钩子。如果你确实需要复制共享资源可以在项目配置中显式开启[markup.goldmark] duplicateResourceFiles true小结Page.Resources是 Hugo 页面资源体系的核心入口ByType按类型批量筛选Get按路径/名称精确定位GetMatch与Match基于大小写不敏感的 glob 模式取首项或全集Mount则将资源重映射为可供importContext使用的 getter。配合 front matter 的resources元数据src/name/title/params与:counter占位符你可以系统化地命名、归档和补充资源信息理解多语言下共享资源的默认去重行为则能帮你写出更高效的国际化站点。相关实现细节可继续阅读 resources/resource/resources.go 与 hugolib/page.go以及文档 docs/content/en/content-management/page-resources.md 和 docs/content/en/content-management/page-bundles.md。【免费下载链接】hugoThe world’s fastest framework for building websites.项目地址: https://gitcode.com/gh_mirrors/hu/hugo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进