Skip to content

Add hugo vendor and resources.Vendor #13309

Closed
@bep

Description

@bep

Note

This proposal is a bit half-baked. I've certainly thought about it a lot over the years, and a concrete implementation popped into my head while sleeping last night, so I thought I'd get it down on paper while it's fresh.

I have spent an excessive amount of time trying to avoid npm as much as possible in Hugo's assets building. However, in some cases, it's hard to avoid. TailwindCSS just released their v4 version, and it's a great piece of software that works well with Hugo.

Unfortunately, this requires npm to be practical.1

We have a new theme for gohugo.io built with TailwindCSS v4 on its way. Unfortunately, currently, you need to do this the first time you're running the site:

npm i
hugo server

This is not ideal if you just want to fix some typos, and it's not great when we include the Hugo documentation in the source distribution (inside /docs in the main repo). I'm betting that people can build the v0.141.0 version of the documentation fairly easily in 20 years. With an npm build step in the mix, all bets are off.

I have thought about ways to fix this, including testing out my own npm Go Module proxy. Below is my latest take on how to solve this in a general way, which should also work for e.g., Dart Sass.

Using TailwindCSS as an example, this is how I imagine it would look in the templates:

{{ with resources.Get "css/styles.css" }}
{{ $opts := dict
   "inlineImports" true
   "optimize" (not hugo.IsDevelopment)
}}
{{ with . | css.TailwindCSS $opts | resources.Vendor }}
 // minify/fingerprint if not dev, insert link
{{ end }}
{{ end }}

resources.Vendor may take options in the future, but for now, I see it as a simple marker that tells Hugo to vendor/use the vendored version of the previous transformation using a shallow key of that transformation's:

  • Transformation key/name
  • Input Resource's Path and Content
  • Options

This is more or less how we do it today for the file cache inside /resources.

We already have a hugo mod vendor command that writes to _vendor. I suggest that we move those down to _vendor/mod so we can add another _vendor/resources root folder for these.

If we then consolidate hugo mod vendor into a new top-level command, we could make it look like:

hugo vendor // all
hugo vendor -mod
hugo vendor -resources

Running hugo vendor -resources will:

  1. Remove _vendor/resources.
  2. Rebuild all vendored assets (transformations tagged with resources.Vendor).

When running hugo or hugo server, we will by default use vendored assets/modules. To enable development, we need to rethink the current --ignoreVendorPaths flag and module config a little.

The above should obviously also work for themes/Hugo Modules. In fact, given how our current vendoring works, it will be great to finally be able to use themes/modules with complex build setups without having anything but hugo installed.

Footnotes

  1. It is possible to download the TailwindCSS CLI binary and put it in the PATH for a npm-less setup (and it may also be worth looking into WebAssembly when we go further down that route), but you quickly find the need for npm once you want to include the great Typography plugin. I guess it's also possible to use the build.useResourceCacheWhen=always, but that's only practical in very simple setups.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions