Hugo - Copying Files to Output Using Pipes
In Hugo, copying files to the output during the build process is a common task, especially when dealing with external resources like CSS, JavaScript, or source maps from node_modules
. In this post, we will walk through how to achieve this without any additional external dependencies.
Resources
- Resources in Hugo are any files that can be processed by Hugo Pipes, such as images, stylesheets, and javascript files.
- These resources can be transformed, minified, concatenated, and otherwise manipulated using Hugo’s built-in functions.
- They are typically placed in the
assets
directory or other mounted directories. - A common method to copy resources involves using
resource.Get
followed byPermalink
,RelPermalink
, orPublish
. - Here’s an example of how to copy a CSS file from
node_modules
to your output:-
First, mount
node_modules
to the assets folder. This can be done inconfig.toml
:1[module] 2[[module.mounts]] 3source = "node_modules" 4target = "assets/vendor"
-
Note that if you do this, you have to explicitly mount other folders too. Defaults are shown in the Hugo documentation here .
-
Now you have to refer to the mount path (i.e.,
assets/vendor
above) when using Hugo pipes to process this file. For example:1{{ $bootstrapCSS := resources.Get "vendor/bootstrap/dist/css/bootstrap.min.css" }} 2<link rel="stylesheet" href="{{ $bootstrapCSS.RelPermalink }}">
-
Non-Resources
-
Non-resources are files that Hugo does not process automatically, such as certain source maps or configuration files.
-
These files might be crucial for development or debugging but are not part of the standard resource pipeline in Hugo.
-
For non-resources, the above approach doesn’t work directly because Hugo doesn’t create resources for them.
-
Instead, you can follow these steps:
- Read the file.
- Use
resources.FromString
. - Publish the resource.
-
To optimize this process, you can create a partial and use it in your layout.
-
Here’s an example partial that can be placed as
layouts/partials/copy-sourcemap-from-nodemodules.html
:1{{ $mapFileOrig := . }} 2{{ $mapFileNode := printf "/node_modules/%s" $mapFileOrig }} 3{{ $mapFileVendor := printf "vendor/%s" $mapFileOrig }} 4{{/* warnf "Source map in: %s, node path: %s vendor path: %s" $mapFileOrig $mapFileNode $mapFileVendor */}} 5{{ $mapContent := readFile $mapFileNode }} 6{{ if $mapContent }} 7 {{ $map := resources.FromString $mapFileVendor $mapContent }} 8 {{ $map.Publish }} 9{{ else }} 10 {{ errorf "Source map not found: %s" $mapFileNode }} 11{{ end }}
-
To use this partial, include it in your template (generally
baseof.html
, etc) like this:1{{ partial "copy-sourcemap-from-nodemodules.html" "bootstrap/dist/css/bootstrap.min.css.map" }}
-
Note that during development, you may need to deleted the output folder and then build your site again for resource copy to work.
Conclusion
By following these steps, you can effectively manage and include both resources and non-resources in your Hugo projects, ensuring that all necessary files are available in the final output.