ESBuild: Looks like we can finally get solid Hugo Modules support

I’ve been playing around with a import resolver implementation with simple test project with project + module on GitHub + a mix of JS and TypeScript and it has been working like a charm:


And the above is probably lacking some context.

The above means that you shortly can just do JS imports of JS files/components that lives inside /assets (which is the full Hugo Modules union filesystem allowing you to override single JS files in a theme/theme component if needed).

If you really want to get rid of NPM/package.json, you can also import third-party JS components directly into your config.toml.

I have tested this with date-fns and it works great:


With the above you can do:

import { addDays } from 'date';

Soonish in a Hugo version near you-


wow, this is going to be incredible.

looking forward to it!

1 Like

I have now found a “scheme” to make this also work great with intellisense (at least in VS Code, but I guess most of “the others” do it mostly the same way).


This is the magic I’ve wanted!


And it works incredibly well.

I have a, admittingly fairly simple project, that has 2 JS modules (a mix of JS and TypeScript)-- and it works flawlessly in VS Code. I have also improved the error messages so you will be taken to the “failing line”. I will also figure out a way to add some data from the templates (which I guess is needed for config settings), but I cannot wait to get this one out into the wild.


@bep … patiently standing by…


Great! Just had to revert a production site back to an old solution after figuring out that the resolver would not work with modules. Looking forward to this!

1 Like

I’m very impressed with this new feature - good work, everyone.
Looking forward to using it…

I’m curious, it looks like tools like Snowpack are not bundling, to allow for Hot Reload without bundling on update. Do you think ESBuild will be fast enough to provide a similar DX?

I think so.

@bep This feature is really nice. But it doens’t work out of the box for index files named index.esm.js. I couldn’t find anything about this in the docs. Currently I’m working with Bootstrap v5 using Hugo modules and it’s awesome!
I have a workaround for now to get this to work, but I think it would be better if we don’t explicitly have to do this. Shall I create an issue regarding this?

    - path:
        - source: scss
          target: assets/scss/bootstrap
        - source: js
          target: assets/bootstrap
        - source: js/index.esm.js
          target: assets/bootstrap/index.js

I import Bootstrap using my wrapper module for it: GitHub - UtkarshVerma/hugo-mod-bootstrap-v5: Hugo module for Bootstrap v5

Yes… But I’m not totally sure what the problem is. Yes, we do have some logic that fall back to “index.js” in there – but I don’t see why you cannot be explicit when doing the imports.

Did you try to exchange those two items? Deeplink first, flatter link then? Looking at the way you solved the _vendor issue this might be the better way and I remember reading somewhere that the mount order is important.

@davidsneighbour I think his message was that his workaround (the extra mount) works, but that it should not be needed.

Ah, ok. The reason then might have to do with all the other index.(*.)js files in that folder. Hugo probably gets confused what to import. I never used the JS part of BS5 yet, so I am of no help here :frowning:

There’s no harm in being explicit, but I when I used Hugo modules for the first time, and after reading the docs mentioning that index.{js,ts,tsx,jsx}, I assumed that it should naturally work for index.esm.js files as well, because NPM takes care of that for me.
For me that was an expected behaviour, but I don’t know if it’s the same for others. Anyhow, I’ll create an issue for this just in case, as you suggested.

Excellent. This is good news. Has this been merged?

Yes. See: