Repository: gohugoio/hugo (language: go)

Issue:
Have ESBuild recognize `index.esm.js` mounted through Hugo modules.
This is in regards to the following discussion:
https://discourse.gohugo.io/t/esbuild-looks-like-we-can-finally-get-solid-hugo-modules-support/28757/12?u=utkarshverma

In short, ESBuild doesn't recognize `index.esm.js` by default, and hence one has to specify an additional export explicitly as such:
```yaml
  imports:
    - path: github.com/twbs/bootstrap
      mounts:
        - source: scss
          target: assets/scss/bootstrap
        - source: js
          target: assets/bootstrap
        - source: js/index.esm.js
          target: assets/bootstrap/index.js
```

As `npm` handles this by default, it would be nice to have this with the ESBuild implementation in Hugo as well. Apart from that, ESBuild modules being relatively new, it took me some time to figure out that an explicit mount for `index.esm.js` was needed.


Discussion / hints:
This issue has been automatically marked as stale because it has not had recent activity. The resources of the Hugo team are limited, and so we are asking for your help.
If this is a **bug** and you can still reproduce this error on the <code>master</code> branch, please reply with all of the information you have about it in order to keep the issue open.
If this is a **feature request**, and you feel that it is still relevant and valuable, please tell us why.
This issue will automatically be closed in the near future if no further activity occurs. Thank you for all your contributions.

Fix patch:
diff --git a/resources/resource_transformers/js/options.go b/resources/resource_transformers/js/options.go
index a0d1b506fdd..2987f5915e1 100644
--- a/resources/resource_transformers/js/options.go
+++ b/resources/resource_transformers/js/options.go
@@ -176,6 +176,12 @@ func resolveComponentInAssets(fs afero.Fs, impPath string) *hugofs.FileMeta {
 	if m != nil {
 		return m
 	}
+	if filepath.Base(impPath) == "index" {
+		m = findFirst(impPath + ".esm")
+		if m != nil {
+			return m
+		}
+	}
 
 	// Finally check the path as is.
 	fi, err := fs.Stat(impPath)
@@ -183,6 +189,9 @@ func resolveComponentInAssets(fs afero.Fs, impPath string) *hugofs.FileMeta {
 	if err == nil {
 		if fi.IsDir() {
 			m = findFirst(filepath.Join(impPath, "index"))
+			if m == nil {
+				m = findFirst(filepath.Join(impPath, "index.esm"))
+			}
 		} else {
 			m = fi.(hugofs.FileMetaInfo).Meta()
 		}


Test patch:
diff --git a/resources/resource_transformers/js/options_test.go b/resources/resource_transformers/js/options_test.go
index 7596f357e05..135164d1848 100644
--- a/resources/resource_transformers/js/options_test.go
+++ b/resources/resource_transformers/js/options_test.go
@@ -150,11 +150,16 @@ func TestResolveComponentInAssets(t *testing.T) {
 		{"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"},
+		{"Index ESM file, folder only", []string{"foo/index.esm.js", "bar.js"}, "foo", "foo/index.esm.js"},
+		{"Index ESM file, folder and index", []string{"foo/index.esm.js", "bar.js"}, "foo/index", "foo/index.esm.js"},
+		{"Index ESM file, folder and index and suffix", []string{"foo/index.esm.js", "bar.js"}, "foo/index.esm.js", "foo/index.esm.js"},
+		// We added these index.esm.js cases in v0.101.0. The case below is unlikely to happen in the wild, but add a test
+		// to document Hugo's behavior. We pick the file with the name index.js; anything else would be breaking.
+		{"Index and Index ESM file, folder only", []string{"foo/index.esm.js", "foo/index.js", "bar.js"}, "foo", "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()