]> git.maquefel.me Git - brevno-suite/hugo/commitdiff
tpl/css: Fix external source maps
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Fri, 13 Mar 2026 15:30:06 +0000 (16:30 +0100)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Sat, 14 Mar 2026 11:08:18 +0000 (12:08 +0100)
Fixes #14620

internal/js/esbuild/build.go
internal/js/esbuild/sourcemap.go
resources/resource_transformers/js/js_integration_test.go
tpl/css/build_integration_test.go

index cf88276c34b436a744c83e9384cec16f08c3e876..a3173a22c24a915383a65e3ffc07248b3b896654 100644 (file)
@@ -225,7 +225,12 @@ func (c *BuildClient) Build(opts Options) (api.BuildResult, error) {
                                        }
                                        return ss
                                }
-                               return ""
+                               if strings.HasPrefix(s, opts.OutDir) {
+                                       // This is an output file, not a source file.
+                                       return ""
+                               }
+                               // s is already the absolute filename set by the Hugo resolve plugin.
+                               return s
                        }
                        return s
                }); err != nil {
index 647f0c0813ad201e64a916c9064f9e4722123db6..036cab29cbc0e9d16d6c20e4dc68b06eeed67261 100644 (file)
@@ -46,7 +46,27 @@ func fixSourceMap(s []byte, resolve func(string) string) ([]byte, error) {
                return nil, err
        }
 
-       sm.Sources = fixSourceMapSources(sm.Sources, resolve)
+       hasSourcesContent := len(sm.SourcesContent) == len(sm.Sources)
+
+       var sources []string
+       var sourcesContent []string
+       for i, src := range sm.Sources {
+               if resolved := resolve(src); resolved != "" {
+                       // Absolute filenames works fine on U*ix (tested in Chrome on MacOs), but works very poorly on Windows (again Chrome).
+                       // So, convert it to a URL.
+                       if u, err := paths.UrlFromFilename(resolved); err == nil {
+                               sources = append(sources, u.String())
+                               if hasSourcesContent {
+                                       sourcesContent = append(sourcesContent, sm.SourcesContent[i])
+                               }
+                       }
+               }
+       }
+
+       sm.Sources = sources
+       if hasSourcesContent {
+               sm.SourcesContent = sourcesContent
+       }
 
        b, err := json.Marshal(sm)
        if err != nil {
@@ -56,20 +76,6 @@ func fixSourceMap(s []byte, resolve func(string) string) ([]byte, error) {
        return b, nil
 }
 
-func fixSourceMapSources(s []string, resolve func(string) string) []string {
-       var result []string
-       for _, src := range s {
-               if s := resolve(src); s != "" {
-                       // Absolute filenames works fine on U*ix (tested in Chrome on MacOs), but works very poorly on Windows (again Chrome).
-                       // So, convert it to a URL.
-                       if u, err := paths.UrlFromFilename(s); err == nil {
-                               result = append(result, u.String())
-                       }
-               }
-       }
-       return result
-}
-
 // Used in tests.
 func SourcesFromSourceMap(s string) []string {
        var sm sourceMap
index 8452c7c40e8b23cc68c55523b1a832ad9fc11eef..ee84ee752e3dcd4091172cd3b0c57c2b5c4c80de 100644 (file)
@@ -228,7 +228,7 @@ TS2: {{ template "print" $ts2 }}
                }
        }
 
-       checkMap("public/js/main.js.map", 4)
+       checkMap("public/js/main.js.map", 5)
 }
 
 func TestBuildError(t *testing.T) {
index 718357de4b9101987ae2379f936f0cbf91e5be54..a36ed0774f6dd9e4eadec84cd6d0df4e1b1ae99e 100644 (file)
@@ -17,8 +17,10 @@ import (
        "strings"
        "testing"
 
+       qt "github.com/frankban/quicktest"
        "github.com/gohugoio/hugo/htesting"
        "github.com/gohugoio/hugo/hugolib"
+       "github.com/gohugoio/hugo/internal/js/esbuild"
 )
 
 func TestCSSBuild(t *testing.T) {
@@ -165,30 +167,45 @@ span { background: green; }
 article { background: yellow; }
 -- layouts/home.html --
 {{ with resources.Get "css/main.css"  }}
-{{ $opts := (dict "minify" false "sourceMap" "SOURCE_MAP" "sourcesContent" SOURCES_CONTENT  "loaders" (dict ".png" "dataurl"))}}
+{{ $opts := (dict "minify" MINIFY "sourceMap" "SOURCE_MAP" "sourcesContent" SOURCES_CONTENT  "loaders" (dict ".png" "dataurl"))}}
 {{ with . | css.Build $opts  }}
  <link rel="stylesheet" href="{{ .RelPermalink }}" />
 {{ end }}
 {{ end }}
        `
 
-       r := strings.NewReplacer(
-               "SOURCE_MAP", "linked",
-               "SOURCES_CONTENT", "true",
+       var (
+               r     *strings.Replacer
+               files string
+               b     *hugolib.IntegrationTestBuilder
        )
 
-       files := r.Replace(filesTemplate)
+       for _, minify := range []string{"true", "false"} {
 
-       b := hugolib.Test(t, files, hugolib.TestOptOsFs())
-       b.AssertFileContent("public/css/main.css", "/*# sourceMappingURL=main.css.map */")
-       b.AssertFileContent("public/css/main.css.map",
-               `"sourcesContent":["p { background: red; }"`,
-               "AAAA;AAAI,cAAY;AAAK",
-       )
+               r = strings.NewReplacer(
+                       "SOURCE_MAP", "linked",
+                       "SOURCES_CONTENT", "true",
+                       "MINIFY", minify,
+               )
+
+               files = r.Replace(filesTemplate)
+
+               b = hugolib.Test(t, files, hugolib.TestOptOsFs())
+               b.AssertFileContent("public/css/main.css", "/*# sourceMappingURL=main.css.map */")
+               b.AssertFileContent("public/css/main.css.map",
+                       `"sourcesContent":["`,
+                       `"mappings":"`,
+               )
+
+               sources := esbuild.SourcesFromSourceMap(b.FileContent("public/css/main.css.map"))
+               // main.css + foo.css + bar.css + baz.css = 4 sources.
+               b.Assert(len(sources), qt.Equals, 4)
+       }
 
        r = strings.NewReplacer(
                "SOURCE_MAP", "external",
                "SOURCES_CONTENT", "true",
+               "MINIFY", "false",
        )
 
        files = r.Replace(filesTemplate)
@@ -203,6 +220,7 @@ article { background: yellow; }
        r = strings.NewReplacer(
                "SOURCE_MAP", "external",
                "SOURCES_CONTENT", "false",
+               "MINIFY", "false",
        )
 
        files = r.Replace(filesTemplate)
@@ -216,6 +234,7 @@ article { background: yellow; }
        r = strings.NewReplacer(
                "SOURCE_MAP", "inline",
                "SOURCES_CONTENT", "false",
+               "MINIFY", "false",
        )
 
        files = r.Replace(filesTemplate)