hugo

Unnamed repository; edit this file 'description' to name the repository.

git clone git://git.shimmy1996.com/hugo.git
commit 32b86076ee1c0833b538b84e1cc9e6d79babecf2
parent 241b7483ea954653512d4895ad6bacf79ee26ddc
Author: Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Date:   Fri, 22 Jan 2021 17:07:23 +0100

js: Add Inject config option

Fixes #8164

Diffstat:
Mdocs/content/en/hugo-pipes/js.md | 3+++
Mhugolib/js_test.go | 8+++++---
Mresources/resource_transformers/js/build.go | 23+++++++++++++++++++++++
Mresources/resource_transformers/js/options.go | 72++++++++++++++++++++++++++++++++++++++++++------------------------------
4 files changed, 73 insertions(+), 33 deletions(-)
diff --git a/docs/content/en/hugo-pipes/js.md b/docs/content/en/hugo-pipes/js.md
@@ -43,6 +43,9 @@ minify [bool]
 avoidTDZ {{< new-in "0.78.0" >}}
 : There is/was a bug in WebKit with severe performance issue with the tracking of TDZ checks in JavaScriptCore. Enabling this flag removes the TDZ and `const` assignment checks and may improve performance of larger JS codebases until the WebKit fix is in widespread use. See https://bugs.webkit.org/show_bug.cgi?id=199866
 
+inject [slice] {{< new-in "0.81.0" >}}
+: This option allows you to automatically replace a global variable with an import from another file. The path names must be relative to `assets`.  See https://esbuild.github.io/api/#inject
+
 shims {{< new-in "0.81.0" >}}
 : This option allows swapping out a component with another. A common use case is to load dependencies like React from a CDN  (with _shims_) when in production, but running with the full bundled `node_modules` dependency during development:
 
diff --git a/hugolib/js_test.go b/hugolib/js_test.go
@@ -187,7 +187,7 @@ path="github.com/gohugoio/hugoTestProjectJSModImports"
         
 go 1.15
         
-require github.com/gohugoio/hugoTestProjectJSModImports v0.8.0 // indirect
+require github.com/gohugoio/hugoTestProjectJSModImports v0.9.0 // indirect
 
 `)
 
@@ -214,10 +214,12 @@ var Hugo = "Rocks!";
 Hello3 from mod2. Date from date-fns: ${today}
 Hello from lib in the main project
 Hello5 from mod2.
-var myparam = "Hugo Rocks!";`)
+var myparam = "Hugo Rocks!";
+shim cwd
+`)
 
 	// React JSX, verify the shimming.
-	b.AssertFileContent("public/js/like.js", `@v0.8.0/assets/js/shims/react.js
+	b.AssertFileContent("public/js/like.js", `@v0.9.0/assets/js/shims/react.js
 module.exports = window.ReactDOM;
 `)
 }
diff --git a/resources/resource_transformers/js/build.go b/resources/resource_transformers/js/build.go
@@ -18,6 +18,7 @@ import (
 	"io/ioutil"
 	"os"
 	"path"
+	"path/filepath"
 	"regexp"
 	"strings"
 
@@ -103,6 +104,28 @@ func (t *buildTransformation) Transform(ctx *resources.ResourceTransformationCtx
 		defer os.Remove(buildOptions.Outdir)
 	}
 
+	if opts.Inject != nil {
+		// Resolve the absolute filenames.
+		for i, ext := range opts.Inject {
+			impPath := filepath.FromSlash(ext)
+			if filepath.IsAbs(impPath) {
+				return errors.Errorf("inject: absolute paths not supported, must be relative to /assets")
+			}
+
+			m := resolveComponentInAssets(t.c.rs.Assets.Fs, impPath)
+
+			if m == nil {
+				return errors.Errorf("inject: file %q not found", ext)
+			}
+
+			opts.Inject[i] = m.Filename()
+
+		}
+
+		buildOptions.Inject = opts.Inject
+
+	}
+
 	result := api.Build(buildOptions)
 
 	if len(result.Errors) > 0 {
diff --git a/resources/resource_transformers/js/options.go b/resources/resource_transformers/js/options.go
@@ -20,6 +20,8 @@ import (
 	"path/filepath"
 	"strings"
 
+	"github.com/spf13/afero"
+
 	"github.com/pkg/errors"
 
 	"github.com/evanw/esbuild/pkg/api"
@@ -64,6 +66,11 @@ type Options struct {
 	// External dependencies, e.g. "react".
 	Externals []string
 
+	// This option allows you to automatically replace a global variable with an import from another file.
+	// The filenames must be relative to /assets.
+	// See https://esbuild.github.io/api/#inject
+	Inject []string
+
 	// User defined symbols.
 	Defines map[string]interface{}
 
@@ -137,6 +144,40 @@ func loaderFromFilename(filename string) api.Loader {
 	return api.LoaderJS
 }
 
+func resolveComponentInAssets(fs afero.Fs, impPath string) hugofs.FileMeta {
+	findFirst := func(base string) hugofs.FileMeta {
+		// This is the most common sub-set of ESBuild's default extensions.
+		// 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 fi, err := fs.Stat(base + ext); err == nil {
+				return fi.(hugofs.FileMetaInfo).Meta()
+			}
+		}
+
+		// Not found.
+		return nil
+	}
+
+	var m hugofs.FileMeta
+
+	// First the path as is.
+	fi, err := fs.Stat(impPath)
+
+	if err == nil {
+		if fi.IsDir() {
+			m = findFirst(filepath.Join(impPath, "index"))
+		} else {
+			m = fi.(hugofs.FileMetaInfo).Meta()
+		}
+	} else {
+		// It may be a regular file imported without an extension.
+		m = findFirst(impPath)
+	}
+
+	return m
+}
+
 func createBuildPlugins(c *Client, opts Options) ([]api.Plugin, error) {
 	fs := c.rs.Assets
 
@@ -169,36 +210,7 @@ func createBuildPlugins(c *Client, opts Options) ([]api.Plugin, error) {
 			impPath = filepath.Join(relDir, impPath)
 		}
 
-		findFirst := func(base string) hugofs.FileMeta {
-			// This is the most common sub-set of ESBuild's default extensions.
-			// 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 fi, err := fs.Fs.Stat(base + ext); err == nil {
-					return fi.(hugofs.FileMetaInfo).Meta()
-				}
-			}
-
-			// Not found.
-			return nil
-		}
-
-		var m hugofs.FileMeta
-
-		// First the path as is.
-		fi, err := fs.Fs.Stat(impPath)
-
-		if err == nil {
-			if fi.IsDir() {
-				m = findFirst(filepath.Join(impPath, "index"))
-			} else {
-				m = fi.(hugofs.FileMetaInfo).Meta()
-			}
-		} else {
-			// It may be a regular file imported without an extension.
-			m = findFirst(impPath)
-		}
-		//
+		m := resolveComponentInAssets(fs.Fs, impPath)
 
 		if m != nil {
 			// Store the source root so we can create a jsconfig.json