ESBuild Live Reloading

Hi, I was just wondering how live reloading interfaces with esbuild. I currently have a partial which conditionally bundles an entry file, however when I change that file, while the site rebuilds (it recognizes that there is a change), it seems like it its not re-bundled.

Is there a way to get around this?

I’m using $ hugo server -D --disableFastRender --gc, in case that helps.

I’m in the process og improving this situation (I have a “almost finished” branch that has been a little too long lived), but for JS bundles the current logic is that they will be rebuilt whenever a JS file (or typescript etc.) file is changed.

I’m not sure why you need the bundle to be rebuilt on partial change?

I’m doing some creative coding stuff and using my hugo site ( to develop as well as to showcase. This is mostly JS stuff + either SVG or Canvas, and I’m using various JS libraries/modules for this work (ex. p5.js, two.js, svg.js).

Currently, I’ve been using NPM at the site level to manage these js dependencies and then using Hugo modules to import/mount the actual library/module from /node_modules/ within /static:

// config.yml
module :
  imports :
    - # svg.js
      disable : false
      path : ../node_modules/@svgdotjs/svg.js
      mounts :
        - source : dist/
          target : static/

Then within my script file I can do something like this:

import { SVG } from '/svg.esm.js'

const sketch = SVG().addTo('[src="script.js"]')
                    .size(500, 500);

// Frequent changes happening here...

This is fine, however it is finicky to maintain (and doesn’t work with the IDE’s knowledge of what is in /node_modules, and the import is happening at run-time (in the browser), which, again, is fine, but it would be good to be able to have the option to bundle/obfuscate/minify.

I have a very strong feeling that this is not the optimal solution. :grimacing:

I’ve thought that Hugo mods could enable a solution (though, I’m not entirely sure how to put it in practice). I also this this in the docs, which seems to address part of what I’m getting at? Though, to be honest, I’m a little lost.

Would love your thoughts.

Me too.

In short, I would recommend that you:

  • Let your NPM packages live in node_modules and avoid mounting anything (and certainly not into static). If you use submodules which also has package.json, see “hugo mod npm pack”
  • I’m not sure what your IDE is (?), but if that has problem with node_modules, you should look at the IDE config and not fight it.
  • As to IDE support for JS packages inside assets, Hugo generetes a jsconfig.js (can be turned off) with the file mappings. I have spent some time in VS Code with it now, and it’s pretty great.

And if you have not seen this already:


Just tried something out quickly … loading from /node_modules and building… seems to work – totally a moment where I’m like : “wow, Hugo has got it! I was making ti waaaay too complicated!” :heart: HUGO

I’m using VS Code… not too worried about this aspect. Seems to work with the above.

Back to my original question about live-reloading. The above seems to not re-build when the entry-point file changes. (Changes reflect when the hole site is rebuilt, though, of course.). Is there a way to force certain builds?

Could it be an issue with content structure?

Here is how I’m running things :

(My real use case is a little more complicated, but I’ve been doing the testing with the logic below)

Reference a Page Resource that you want to bundle + insert:

// /content/page-a/

{{< bundle src="script.js" >}} // Changes happening in `script.js`

Which outputs :

<script src="absolute/path/.../script.bundle.js">

So, what is happening now is that if script.js changes from

import 'some-module' // not really relevant 


import 'some-module' // again, not really relevant 

Hugo is recognizing the change (as per the terminal) but the bundle is not changing. (still getting ‘hi’ in the terminal)

Just another thought: I know that ESBuild does it’s file watching/serving a little different from most – rebuilding on reload. is this the issue/reason?

Seems to be a cacheing issues (?)

when I make the target name change (via adding the Unix time to it), the changes are reflected.

Not sure if this is ideal, but the hack works…

the shortcode:

{{- $src := .Get "src" | default "" -}}

{{- $name := replaceRE `(.+).js$` `$1` $src -}}
{{- $target := printf "%s.bundle-%d.js" $name now.Unix -}}
{{- $built := $.Page.Resources.GetMatch $src | js.Build $target -}}

<script src="{{ $built.Permalink }}"></script>

No this is entirely a Hugo “thing”.

I have this hack (?) working, should I open an issue on github, or leave be?

Leave. There are plenty of related issues. As I said, I’m aware of the limitations/areas of improvements.

1 Like

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.