Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/gohugoio/hugo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2020-07-21 18:59:03 +0300
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2020-07-22 11:13:30 +0300
commit0256959a358bb26b983c9d9496862b0fdf387621 (patch)
tree35578577001fb8bf330cae72195251cd73ce777d /resources
parenteded9ac2a05b9a7244c25c70ca8f761b69b33385 (diff)
resources/js: Add option for setting bundle format
Fixes #7503
Diffstat (limited to 'resources')
-rw-r--r--resources/postpub/fields_test.go1
-rw-r--r--resources/resource_transformers/js/build.go126
-rw-r--r--resources/resource_transformers/js/build_test.go34
3 files changed, 119 insertions, 42 deletions
diff --git a/resources/postpub/fields_test.go b/resources/postpub/fields_test.go
index fa0c9190a..d67c7c9a9 100644
--- a/resources/postpub/fields_test.go
+++ b/resources/postpub/fields_test.go
@@ -32,6 +32,7 @@ func TestCreatePlaceholders(t *testing.T) {
c.Assert(m, qt.DeepEquals, map[string]interface{}{
"FullSuffix": "pre_foo.FullSuffix_post",
+ "IsZero": "pre_foo.IsZero_post",
"Type": "pre_foo.Type_post",
"MainType": "pre_foo.MainType_post",
"Delimiter": "pre_foo.Delimiter_post",
diff --git a/resources/resource_transformers/js/build.go b/resources/resource_transformers/js/build.go
index 488c6d1a4..8e0c7c130 100644
--- a/resources/resource_transformers/js/build.go
+++ b/resources/resource_transformers/js/build.go
@@ -33,8 +33,6 @@ import (
"github.com/gohugoio/hugo/resources/resource"
)
-const defaultTarget = "esnext"
-
type Options struct {
// If not set, the source path will be used as the base target path.
// Note that the target path's extension may change if the target MIME type
@@ -49,6 +47,11 @@ type Options struct {
// Default is esnext.
Target string
+ // The output format.
+ // One of: iife, cjs, esm
+ // Default is to esm.
+ Format string
+
// External dependencies, e.g. "react".
Externals []string `hash:"set"`
@@ -60,25 +63,29 @@ type Options struct {
// What to use instead of React.Fragment.
JSXFragment string
+
+ mediaType media.Type
+ outDir string
+ contents string
+ sourcefile string
+ resolveDir string
}
-func decodeOptions(m map[string]interface{}) (opts Options, err error) {
- err = mapstructure.WeakDecode(m, &opts)
- if err != nil {
- return
+func decodeOptions(m map[string]interface{}) (Options, error) {
+ var opts Options
+
+ if err := mapstructure.WeakDecode(m, &opts); err != nil {
+ return opts, err
}
if opts.TargetPath != "" {
opts.TargetPath = helpers.ToSlashTrimLeading(opts.TargetPath)
}
- if opts.Target == "" {
- opts.Target = defaultTarget
- }
-
opts.Target = strings.ToLower(opts.Target)
+ opts.Format = strings.ToLower(opts.Format)
- return
+ return opts, nil
}
type Client struct {
@@ -114,9 +121,40 @@ func (t *buildTransformation) Transform(ctx *resources.ResourceTransformationCtx
ctx.ReplaceOutPathExtension(".js")
}
+ src, err := ioutil.ReadAll(ctx.From)
+ if err != nil {
+ return err
+ }
+
+ sdir, sfile := path.Split(ctx.SourcePath)
+ opts.sourcefile = sfile
+ opts.resolveDir = t.sfs.RealFilename(sdir)
+ opts.contents = string(src)
+ opts.mediaType = ctx.InMediaType
+
+ buildOptions, err := toBuildOptions(opts)
+ if err != nil {
+ return err
+ }
+
+ result := api.Build(buildOptions)
+ if len(result.Errors) > 0 {
+ return fmt.Errorf("%s", result.Errors[0].Text)
+ }
+ ctx.To.Write(result.OutputFiles[0].Contents)
+ return nil
+}
+
+func (c *Client) Process(res resources.ResourceTransformer, opts map[string]interface{}) (resource.Resource, error) {
+ return res.Transform(
+ &buildTransformation{rs: c.rs, sfs: c.sfs, optsm: opts},
+ )
+}
+
+func toBuildOptions(opts Options) (buildOptions api.BuildOptions, err error) {
var target api.Target
switch opts.Target {
- case defaultTarget:
+ case "", "esnext":
target = api.ESNext
case "es5":
target = api.ES5
@@ -133,11 +171,17 @@ func (t *buildTransformation) Transform(ctx *resources.ResourceTransformationCtx
case "es2020":
target = api.ES2020
default:
- return fmt.Errorf("invalid target: %q", opts.Target)
+ err = fmt.Errorf("invalid target: %q", opts.Target)
+ return
+ }
+
+ mediaType := opts.mediaType
+ if mediaType.IsZero() {
+ mediaType = media.JavascriptType
}
var loader api.Loader
- switch ctx.InMediaType.SubType {
+ switch mediaType.SubType {
// TODO(bep) ESBuild support a set of other loaders, but I currently fail
// to see the relevance. That may change as we start using this.
case media.JavascriptType.SubType:
@@ -149,29 +193,43 @@ func (t *buildTransformation) Transform(ctx *resources.ResourceTransformationCtx
case media.JSXType.SubType:
loader = api.LoaderJSX
default:
- return fmt.Errorf("unsupported Media Type: %q", ctx.InMediaType)
-
+ err = fmt.Errorf("unsupported Media Type: %q", opts.mediaType)
+ return
}
- src, err := ioutil.ReadAll(ctx.From)
- if err != nil {
- return err
+ var format api.Format
+ // One of: iife, cjs, esm
+ switch opts.Format {
+ case "", "iife":
+ format = api.FormatIIFE
+ case "esm":
+ format = api.FormatESModule
+ case "cjs":
+ format = api.FormatCommonJS
+ default:
+ err = fmt.Errorf("unsupported script output format: %q", opts.Format)
+ return
+
}
- sdir, sfile := path.Split(ctx.SourcePath)
- sdir = t.sfs.RealFilename(sdir)
+ var defines map[string]string
+ if opts.Defines != nil {
+ defines = cast.ToStringMapString(opts.Defines)
+ }
- buildOptions := api.BuildOptions{
+ buildOptions = api.BuildOptions{
Outfile: "",
Bundle: true,
Target: target,
+ Format: format,
MinifyWhitespace: opts.Minify,
MinifyIdentifiers: opts.Minify,
MinifySyntax: opts.Minify,
- Defines: cast.ToStringMapString(opts.Defines),
+ Outdir: opts.outDir,
+ Defines: defines,
Externals: opts.Externals,
@@ -181,26 +239,12 @@ func (t *buildTransformation) Transform(ctx *resources.ResourceTransformationCtx
//Tsconfig: opts.TSConfig,
Stdin: &api.StdinOptions{
- Contents: string(src),
- Sourcefile: sfile,
- ResolveDir: sdir,
+ Contents: opts.contents,
+ Sourcefile: opts.sourcefile,
+ ResolveDir: opts.resolveDir,
Loader: loader,
},
}
- result := api.Build(buildOptions)
- if len(result.Errors) > 0 {
- return fmt.Errorf("%s", result.Errors[0].Text)
- }
- if len(result.OutputFiles) != 1 {
- return fmt.Errorf("unexpected output count: %d", len(result.OutputFiles))
- }
-
- ctx.To.Write(result.OutputFiles[0].Contents)
- return nil
-}
+ return
-func (c *Client) Process(res resources.ResourceTransformer, opts map[string]interface{}) (resource.Resource, error) {
- return res.Transform(
- &buildTransformation{rs: c.rs, sfs: c.sfs, optsm: opts},
- )
}
diff --git a/resources/resource_transformers/js/build_test.go b/resources/resource_transformers/js/build_test.go
index 2e4c174f7..ee97dede5 100644
--- a/resources/resource_transformers/js/build_test.go
+++ b/resources/resource_transformers/js/build_test.go
@@ -16,6 +16,10 @@ package js
import (
"testing"
+ "github.com/gohugoio/hugo/media"
+
+ "github.com/evanw/esbuild/pkg/api"
+
qt "github.com/frankban/quicktest"
)
@@ -26,9 +30,37 @@ func TestOptionKey(t *testing.T) {
opts := map[string]interface{}{
"TargetPath": "foo",
+ "Target": "es2018",
}
key := (&buildTransformation{optsm: opts}).Key()
- c.Assert(key.Value(), qt.Equals, "jsbuild_15565843046704064284")
+ c.Assert(key.Value(), qt.Equals, "jsbuild_7891849149754191852")
+}
+
+func TestToBuildOptions(t *testing.T) {
+ c := qt.New(t)
+
+ opts, err := toBuildOptions(Options{mediaType: media.JavascriptType})
+ c.Assert(err, qt.IsNil)
+ c.Assert(opts, qt.DeepEquals, api.BuildOptions{
+ Bundle: true,
+ Target: api.ESNext,
+ Format: api.FormatIIFE,
+ Stdin: &api.StdinOptions{},
+ })
+
+ opts, err = toBuildOptions(Options{
+ Target: "es2018", Format: "cjs", Minify: true, mediaType: media.JavascriptType})
+ c.Assert(err, qt.IsNil)
+ c.Assert(opts, qt.DeepEquals, api.BuildOptions{
+ Bundle: true,
+ Target: api.ES2018,
+ Format: api.FormatCommonJS,
+ MinifyIdentifiers: true,
+ MinifySyntax: true,
+ MinifyWhitespace: true,
+ Stdin: &api.StdinOptions{},
+ })
+
}