js.Build loaders

I’m trying to use the js.Build loaders feature and am not able to replace the loader for .css with text to import the CSS file as a string in JS.

I usually use the esbuild CLI to debug issues, in this case like this:

esbuild --bundle  --loader:.css=text   assets/js/print.js

While the above works, the following (truncated, see example from the link above) doesn’t

      {{$opts := dict
        "minify" (not hugo.IsDevelopment)
        "sourceMap" (cond hugo.IsDevelopment "external" "")
        "targetPath" "js/print.js"
        "loaders" (dict ".json" "json" ".css" "text")
        "target" "es2020"
      }}
      {{ with . | js.Build $opts }}

The errors are:

ERROR js.Build failed: No loader is configured for ".png" files: node_modules/leaflet/dist/images/layers-2x.png
ERROR js.Build failed: No loader is configured for ".png" files: node_modules/leaflet/dist/images/marker-icon.png

This indicates a few things:

  • Resolution works
  • The resolved file is handled as CSS (it tries to load images referenced by the CSS url() function) not as text as expected

Am I missing something or might there be a bug?

Update

By accident I found out that this might be a a timing problem:

The problematic import is this:

import cssStyle from "leaflet/dist/leaflet.css";

When I comment it out, I can start hugo server, when it’s running I can comment it in again and then it’s working. When I stop Hugo afterwards and restart, it fails again, as above…

Run hugo to create the site without the dev server and you will see that it’s not a “timing issue”, but the server probably ignoring the issue when it’s commented out and in. It’s IMHO a “double import”, as in you import the leaflet css, which imports png images and esbuild somehow does not know how to handle the png imports. Either manually handle the issue by copying the leaflet.css and “fixing” the imports in there, or (disclaimer, I didn’t try it within Hugo) follow the docs that sound like you could add a loader for .png files named dataurl which should lead to inline images in your CSS. Careful, it will handle all imports of png files that way and it might blow up your css file size. binary or copy might be another option.

Well, thanks.

But the PNG error just implies that, the loader isn’t passed initially: When the CSS would be parsed as text then Esbuild wouldn’t try to load references from the CSS file, since trying to resolve url() functions calls is a clear indication taht the text loader isn’t applied in the first place. I aware that there are workarounds. But that isn’t the question here.
And the thing is, when doing the change while the dev server is running, not only does the message disappear but the contents of the file get available as text inside the script as well.

The whole point of the text loader is to make sure that Esbuild doesn’t try to load the PNG images as well…
And trying to change the loader for PNG to dataurl or even none won’t help either since also this config won’t get applied…

Where do you define the text loader for the .png format?

 "loaders" (dict ".json" "json" ".css" "text")

that should probably be done here.

It wasn’t part of the example since it’s not relevant: Loading CSS as text won’t require one since it should not be triggered…
It’s part of the problem that some component even tries…

I might have tracked it down: there seem to be a dependency on a output format with another js.Build config on my side this triggers this during the initial build.

Maybe js.Build is only initialized once and then reused?

Ive created a bug on this:

There’s a cache, but the options map is part of the cache key … That said, I will have a look at this before the next Hugo release.