diff --git a/internal/js/esbuild/options.go b/internal/js/esbuild/options.go index 32d2a6251..e5309fbbe 100644 --- a/internal/js/esbuild/options.go +++ b/internal/js/esbuild/options.go @@ -299,6 +299,15 @@ OUTER: } loaders[k] = loader } + } else if opts.IsCSS { + loaders = make(map[string]api.Loader) + // For CSS builds, default to the file loader for common static + // file extensions so that url() references are handled correctly + // even when resolved by ESBuild's native resolver. + // See #14619. + for _, ext := range defaultCSSFileLoaderExts { + loaders[ext] = api.LoaderFile + } } mediaType := opts.MediaType @@ -467,16 +476,14 @@ func (o Options) loaderFromFilename(filename string) api.Loader { if found { return l } - // For CSS builds, handling, default to the file loader for unknown extensions. - return api.LoaderFile } else { l, found := extensionToLoaderMapJS[ext] if found { return l } - } - return api.LoaderJS + } + return api.LoaderDefault } func (opts *Options) validate() error { diff --git a/internal/js/esbuild/resolve.go b/internal/js/esbuild/resolve.go index e9cfa7f9b..3bdfda2da 100644 --- a/internal/js/esbuild/resolve.go +++ b/internal/js/esbuild/resolve.go @@ -62,6 +62,12 @@ var extensionToLoaderMapCSS = map[string]api.Loader{ ".css": api.LoaderCSS, } +// Common static file extensions that should use the file loader in CSS builds. +var defaultCSSFileLoaderExts = []string{ + ".png", ".jpg", ".jpeg", ".gif", ".svg", ".webp", ".avif", + ".woff", ".woff2", ".ttf", ".eot", ".otf", +} + // This is a common sub-set of ESBuild's default extensions. // We assume that imports of JSON, CSS etc. will be using their full // name with extension. diff --git a/tpl/css/build_integration_test.go b/tpl/css/build_integration_test.go index c294452b7..718357de4 100644 --- a/tpl/css/build_integration_test.go +++ b/tpl/css/build_integration_test.go @@ -270,10 +270,15 @@ func TestCSSBuildLoadersDefault(t *testing.T) { -- hugo.toml -- -- assets/a/pixel.png -- iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg== +-- static/b/issue14619.png -- +iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg== -- assets/css/main.css -- body { background-image: url("a/pixel.png"); } +div { + background-image: url("static/b/issue14619.png"); +} -- layouts/home.html -- {{ with resources.Get "css/main.css" }} {{ with . | css.Build (dict "minify" true) }} @@ -285,6 +290,8 @@ body { b := hugolib.Test(t, files, hugolib.TestOptOsFs()) b.AssertFileContent("public/css/main.css", `./pixel-NJRUOINY.png`) b.AssertFileExists("public/css/pixel-NJRUOINY.png", true) + b.AssertFileContent("public/css/main.css", `url("./issue14619-NJRUOINY.png")`) + b.AssertFileExists("public/css/issue14619-NJRUOINY.png", true) } func TestCSSBuildBootstrapFromNPM(t *testing.T) {