-
-
Notifications
You must be signed in to change notification settings - Fork 8.1k
Description
I want to run in a --strict mode that fails if I have:
- Unused params
- Unused frontmatter keys
- broken links (either to images or other articles), at least internal links
- unused i18n keys (https://stackoverflow.com/questions/78436641/unused-i18n-keys-and-duplicate-keys-in-hugo)
And possibly other issues with the code that are most likely unintentional.
I also find the existing solutions to failing on internal links unsatisfactory. I'm not sure if GPT-5 is providing the best solution, but I don't want to make a file manually in all hugo repos to make invalid links fail the build, that should ideally be provided by the framework.
GPT-5:
Short answer:
- You can’t reliably use
refinside Markdown link syntax like[text]({{< ref "..." >}})anymore. Hugo calls theref/relrefshortcodes “obsolete for Markdown” and recommends the embedded link render hook instead. ([gohugo.io]1) - You can fail the build for Markdown links (and images) that point to missing internal targets by adding link/image render hooks that
errorfwhen resolution fails. This runs at render time, before the site is written. ([gohugo.io]2) - For external URLs (http/https), Hugo won’t fetch them during render. Use a post-build checker (e.g., Lychee/Muffet) in CI to fail on 404s. ([Well-Shaped Words]3)
Make Markdown links fail the build (internal only)
1) Enable/use the embedded hooks
# hugo.toml
[markup.goldmark.renderHooks.link]
useEmbedded = "always" # auto|fallback|never|always
[markup.goldmark.renderHooks.image]
useEmbedded = "always"This lets Hugo resolve Markdown destinations the same way it resolves ref/relref. ([gohugo.io]2)
2) Add render-link.html that validates + errors
layouts/_default/_markup/render-link.html:
{{- $u := urls.Parse .Destination -}}
{{- $isAbs := or (ne $u.Scheme "") (strings.HasPrefix .Destination "//") -}}
{{- if not $isAbs -}}
{{/* Try to resolve internal target: page → page resource → global resource */}}
{{- $page := site.GetPage $u.Path | default (.Page.GetPage $u.Path) -}}
{{- $res := cond (not $page) (resources.Get $u.Path) nil -}}
{{- if not (or $page $res) -}}
{{- errorf "Broken internal link %q on %s" .Destination .Page.File.Path -}}
{{- end -}}
{{- if and $page $u.Fragment -}}
{{- if not ($page.Fragments.Identifiers.Contains $u.Fragment) -}}
{{- errorf "Broken fragment #%s in link %q on %s" $u.Fragment .Destination .Page.File.Path -}}
{{- end -}}
{{- end -}}
{{- end -}}
<a href="{{ .Destination | safeURL }}">{{ .Text | safeHTML }}</a>
Notes:
.Fragments.Identifiers.Containsgives you reliable, GitHub-style heading id checks. ([gohugo.io]4)- Use
warnfinstead oferrorfif you want warnings, then combine with--panicOnWarningto fail the build. ([HUGO]5)
3) Do the same for images
layouts/_default/_markup/render-image.html:
{{- $u := urls.Parse .Destination -}}
{{- $isAbs := or (ne $u.Scheme "") (strings.HasPrefix .Destination "//") -}}
{{- if not $isAbs -}}
{{- $img := .Page.Resources.GetMatch $u.Path | default (resources.Get $u.Path) -}}
{{- if not $img -}}
{{- errorf "Broken internal image %q on %s" .Destination .Page.File.Path -}}
{{- end -}}
{{- end -}}
<img src="{{ .Destination | safeURL }}" alt="{{ .Text }}" />
This catches missing page/global resources referenced via Markdown images. ([gohugo.io]6)
What about external links/images?
Hugo’s render hooks don’t fetch remote URLs, so they can’t know if https://… returns 404. Run a link checker after hugo in CI and fail if any external links are dead (e.g., Lychee or Muffet). ([Well-Shaped Words]3)