Master Hugo modules: handle content or assets as modules
This is part two of the Master Hugo Modules series. Be sure you’ve completed part one, Managing Themes as Modules: this article requires that your parent project already be set up as a Hugo module.
What’s a Hugo module for content or assets?
Hugo Modules are the core building blocks in Hugo. A module can be your main project or a smaller module providing one or more of the 7 component types defined in Hugo: static, content, layouts, data, assets, i18n, and archetypes. (Hugo Documentation)
A Hugo content or asset module is an external dependency that provides content or asset resources, but not within your Hugo project’s regular /content
or /asset
directories. Content and asset modules are ideal for read-only content that doesn’t change often. Standardized typographic style guides, shared brand assets, or icon libraries are great examples. At large organizations with multiple websites, content modules can ensure the uniformity of legally-required text like privacy policies, terms of service, copyright, or licensing information.
Why use content or asset modules?
Modules improve developer and editorial workflow. In the past, I’ve copy-and-pasted a typographic style guide from a master repository to each project that needed it… but that’s chunky and error-prone. Moreover, improvements aren’t propagated back upstream without extra effort. But the read-only nature of a content module pushes ongoing improvement upstream: it improves the quality of a library for all projects, by collecting changes as it is implemented in different projects.
This is especially valuable for teams managing multiple sites: consider agencies working with different organizations, or a company working with different brand sites. A well-managed library helps ensure uniformity and consistency.
How to set up a Hugo content module
Create and configure the module
Creating a content or asset module is easy. First, create your repository, and add the content that you wish to share. You can structure this as you like. It’s not required, but consider using the Hugo component /asset
and /content
directories to keep things orderly.
Once your repo is ready for sharing, you’ll need to initialize it as a Hugo module:
hugo mod init <path-and-repo-name>
Pay attention to this name: the parent projects that will consume this module uses the module name. After hugo mod init
, you’ll see a go.mod
in the project root. Commit everything, then turn to the parent project that will use this module.
Add the content module to the parent project
To use a content module, you’ll update your parent project’s config.toml
. You’ll indicate where the module is located, the source directory you want to use, and the “virtual” mount location within your own project. This is described as a file mount: it’s as if this module were located at the target path specified.
For a test, I created a typographic style guide module. It can be mounted to a parent Hugo project like so:
[module]
[module.imports]
path = "gitlab.com/neotericdesign-tools/hugo-content-module-style-guides.git"
[module.imports.mounts]
source = "content/style-guides"
target = "content/style-guides"
Hugo can pick up this module in a few ways. If you run your standard hugo server
and the module isn’t yet registered, it will be — downloaded locally, with your go.mod
file updated accordingly. If you want to test paths first,hugo mod get
will explicitly pull the module. It’s always a fine practice to see the external dependencies: hugo mod vendor
adds them as overrides to the _vendor
folder, where you can see the markdown content, treated as if it were in your parent project’s /content/style-guides/
folder.
Add an asset module to a Hugo project
Bjørn Erik Pedersen has made the MIT-licensed HeroIcons available as a Hugo asset module. Add the external module to the parent Hugo project:
[[module.imports]]
path = "github.com/gohugoio/hugo-mod-heroicons"
And now, in your templates, you can call any of the assets as if they were at /assets/svg/heroicons/
:
{{ $icon := resources.Get "svg/heroicons/outline/search.svg" }}
{{ $icon.Content | safeHTML }}
Note in this case, I didn’t explicitly declare the file mount source and targets. Instead, they were declared in the module’s own config.toml.
What about headless CMSes?
Git-based headless CMSes like Forestry and NetlifyCMS won’t see content or asset modules, and so, won’t present them as available to the site editor. Just as well, since these are read-only from the perspective of the parent project. A note in the documentation (“How do I get to…”) can help clear up this fantom content.
Up next in the Mastering Hugo Modules series
Folding content and asset modules into your project workflow will help for any projects that have shared assets: brand style guides, logo assets, and more are now readily and consistently available. The next articles will consider private repos — not everything can be public after all — as well as module development time and modules and functions. Feel free to drop me a note on Twitter if you have ideas or questions.