diff --git a/go.sum b/go.sum index 3922f6bc4..444547656 100644 --- a/go.sum +++ b/go.sum @@ -188,6 +188,12 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanw/esbuild v0.8.39 h1:/kOe+5zUXSzB2y2m/BxgNsQ5wpgbcGU2uE6MBVSleww= +github.com/evanw/esbuild v0.8.39/go.mod h1:y2AFBAGVelPqPodpdtxWWqe6n2jYf5FrsJbligmRmuw= +github.com/evanw/esbuild v0.10.2 h1:aTkCGE1R5YYhXl375VKQKtJmW85mnsGo15KW5nnYYIs= +github.com/evanw/esbuild v0.10.2/go.mod h1:y2AFBAGVelPqPodpdtxWWqe6n2jYf5FrsJbligmRmuw= +github.com/evanw/esbuild v0.11.23 h1:Y5I6OTABHBmOmt2cbRKrByW5sLdTrpaWhV2MihqLLiw= +github.com/evanw/esbuild v0.11.23/go.mod h1:y2AFBAGVelPqPodpdtxWWqe6n2jYf5FrsJbligmRmuw= github.com/evanw/esbuild v0.12.24 h1:AlNPVfiY7tc6Di54tm6MngT2MpWVUleBc/Rg3wlr8rI= github.com/evanw/esbuild v0.12.24/go.mod h1:y2AFBAGVelPqPodpdtxWWqe6n2jYf5FrsJbligmRmuw= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= diff --git a/resources/resource_transformers/js/options.go b/resources/resource_transformers/js/options.go index d1359ebda..9d2bb2e70 100644 --- a/resources/resource_transformers/js/options.go +++ b/resources/resource_transformers/js/options.go @@ -149,6 +149,10 @@ func resolveComponentInAssets(fs afero.Fs, impPath string) *hugofs.FileMeta { // We assume that imports of JSON, CSS etc. will be using their full // name with extension. for _, ext := range []string{".js", ".ts", ".tsx", ".jsx"} { + if strings.HasSuffix(impPath, ext) { + // Import of foo.js.js need the full name. + return nil + } if fi, err := fs.Stat(base + ext); err == nil { return fi.(hugofs.FileMetaInfo).Meta() } @@ -160,7 +164,21 @@ func resolveComponentInAssets(fs afero.Fs, impPath string) *hugofs.FileMeta { var m *hugofs.FileMeta - // First the path as is. + // See issue #8949. + // We need to check if this is a regular file imported without an extension. + // There may be ambigous situations where both foo.js and foo/index.js exists. + // This import order is in line with both how Node and ESBuild's native + // import resolver works. + // This was fixed in Hugo 0.88. + + // It may be a regular file imported without an extension, e.g. + // foo or foo/index. + m = findFirst(impPath) + if m != nil { + return m + } + + // Finally check the path as is. fi, err := fs.Stat(impPath) if err == nil { @@ -169,9 +187,6 @@ func resolveComponentInAssets(fs afero.Fs, impPath string) *hugofs.FileMeta { } else { m = fi.(hugofs.FileMetaInfo).Meta() } - } else { - // It may be a regular file imported without an extension. - m = findFirst(impPath) } return m diff --git a/resources/resource_transformers/js/options_test.go b/resources/resource_transformers/js/options_test.go index c178ee8c9..e5b04e355 100644 --- a/resources/resource_transformers/js/options_test.go +++ b/resources/resource_transformers/js/options_test.go @@ -14,8 +14,13 @@ package js import ( + "path/filepath" "testing" + "github.com/gohugoio/hugo/hugofs" + + "github.com/spf13/afero" + "github.com/gohugoio/hugo/media" "github.com/evanw/esbuild/pkg/api" @@ -127,3 +132,48 @@ func TestToBuildOptions(t *testing.T) { }, }) } + +func TestResolveComponentInAssets(t *testing.T) { + c := qt.New(t) + + for _, test := range []struct { + name string + files []string + impPath string + expect string + }{ + {"Basic, extension", []string{"foo.js", "bar.js"}, "foo.js", "foo.js"}, + {"Basic, no extension", []string{"foo.js", "bar.js"}, "foo", "foo.js"}, + {"Basic, no extension, typescript", []string{"foo.ts", "bar.js"}, "foo", "foo.ts"}, + {"Not found", []string{"foo.js", "bar.js"}, "moo.js", ""}, + {"Not found, double js extension", []string{"foo.js.js", "bar.js"}, "foo.js", ""}, + {"Index file, folder only", []string{"foo/index.js", "bar.js"}, "foo", "foo/index.js"}, + {"Index file, folder and index", []string{"foo/index.js", "bar.js"}, "foo/index", "foo/index.js"}, + {"Index file, folder and index and suffix", []string{"foo/index.js", "bar.js"}, "foo/index.js", "foo/index.js"}, + + // Issue #8949 + {"Check file before directory", []string{"foo.js", "foo/index.js"}, "foo", "foo.js"}, + } { + + c.Run(test.name, func(c *qt.C) { + baseDir := "assets" + mfs := afero.NewMemMapFs() + + for _, filename := range test.files { + c.Assert(afero.WriteFile(mfs, filepath.Join(baseDir, filename), []byte("let foo='bar';"), 0777), qt.IsNil) + } + + bfs := hugofs.DecorateBasePathFs(afero.NewBasePathFs(mfs, baseDir).(*afero.BasePathFs)) + + got := resolveComponentInAssets(bfs, test.impPath) + + gotPath := "" + if got != nil { + gotPath = filepath.ToSlash(got.Path) + } + + c.Assert(gotPath, qt.Equals, test.expect) + }) + + } +}