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-12 13:47:14 +0300
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2020-07-13 11:56:23 +0300
commit9df98ec49ca9fa326125ccfee626b6e46c6ab14b (patch)
treecdfcfcc9522366d69b7b543638b689852a5e1252 /resources
parent2fc33807077cd25bf91f2298bf1a8ace126881a7 (diff)
Add proper Media Type handling in js.Build
See #732
Diffstat (limited to 'resources')
-rw-r--r--resources/resource_transformers/js/build.go109
-rw-r--r--resources/resource_transformers/js/build_test.go69
2 files changed, 151 insertions, 27 deletions
diff --git a/resources/resource_transformers/js/build.go b/resources/resource_transformers/js/build.go
index 6224ee178..c48778692 100644
--- a/resources/resource_transformers/js/build.go
+++ b/resources/resource_transformers/js/build.go
@@ -17,8 +17,11 @@ import (
"fmt"
"io/ioutil"
"path"
+ "strings"
+ "github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/hugolib/filesystems"
+ "github.com/gohugoio/hugo/media"
"github.com/gohugoio/hugo/resources/internal"
"github.com/mitchellh/mapstructure"
@@ -28,15 +31,46 @@ 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
+ // is different, e.g. when the source is TypeScript.
+ TargetPath string
+
+ // Whether to minify to output.
+ Minify bool
+
+ // The language target.
+ // One of: es2015, es2016, es2017, es2018, es2019, es2020 or esnext.
+ // Default is esnext.
+ Target string
+
+ // External dependencies, e.g. "react".
+ Externals []string `hash:"set"`
+
+ // What to use instead of React.createElement.
+ JSXFactory string
+
+ // What to use instead of React.Fragment.
+ JSXFragment string
+}
+
+type internalOptions struct {
+ TargetPath string
Minify bool
- Externals []string
Target string
- Loader string
- Defines map[string]string
JSXFactory string
JSXFragment string
- TSConfig string
+
+ Externals []string `hash:"set"`
+
+ // These are currently not exposed in the public Options struct,
+ // but added here to make the options hash as stable as possible for
+ // whenever we do.
+ Defines map[string]string
+ TSConfig string
}
func DecodeOptions(m map[string]interface{}) (opts Options, err error) {
@@ -44,6 +78,13 @@ func DecodeOptions(m map[string]interface{}) (opts Options, err error) {
return
}
err = mapstructure.WeakDecode(m, &opts)
+
+ if opts.TargetPath != "" {
+ opts.TargetPath = helpers.ToSlashTrimLeading(opts.TargetPath)
+ }
+
+ opts.Target = strings.ToLower(opts.Target)
+
return
}
@@ -57,7 +98,7 @@ func New(fs *filesystems.SourceFilesystem, rs *resources.Spec) *Client {
}
type buildTransformation struct {
- options Options
+ options internalOptions
rs *resources.Spec
sfs *filesystems.SourceFilesystem
}
@@ -67,9 +108,17 @@ func (t *buildTransformation) Key() internal.ResourceTransformationKey {
}
func (t *buildTransformation) Transform(ctx *resources.ResourceTransformationCtx) error {
+ ctx.OutMediaType = media.JavascriptType
+
+ if t.options.TargetPath != "" {
+ ctx.OutPath = t.options.TargetPath
+ } else {
+ ctx.ReplaceOutPathExtension(".js")
+ }
+
var target api.Target
switch t.options.Target {
- case "", "esnext":
+ case defaultTarget:
target = api.ESNext
case "es6", "es2015":
target = api.ES2015
@@ -88,29 +137,20 @@ func (t *buildTransformation) Transform(ctx *resources.ResourceTransformationCtx
}
var loader api.Loader
- switch t.options.Loader {
- case "", "js":
+ switch ctx.InMediaType.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:
loader = api.LoaderJS
- case "jsx":
- loader = api.LoaderJSX
- case "ts":
+ case media.TypeScriptType.SubType:
loader = api.LoaderTS
- case "tsx":
+ case media.TSXType.SubType:
loader = api.LoaderTSX
- case "json":
- loader = api.LoaderJSON
- case "text":
- loader = api.LoaderText
- case "base64":
- loader = api.LoaderBase64
- case "dataURL":
- loader = api.LoaderDataURL
- case "file":
- loader = api.LoaderFile
- case "binary":
- loader = api.LoaderBinary
+ case media.JSXType.SubType:
+ loader = api.LoaderJSX
default:
- return fmt.Errorf("invalid loader: %q", t.options.Loader)
+ return fmt.Errorf("unsupported Media Type: %q", ctx.InMediaType)
+
}
src, err := ioutil.ReadAll(ctx.From)
@@ -159,8 +199,23 @@ func (t *buildTransformation) Transform(ctx *resources.ResourceTransformationCtx
return nil
}
-func (c *Client) Process(res resources.ResourceTransformer, options Options) (resource.Resource, error) {
+func (c *Client) Process(res resources.ResourceTransformer, opts Options) (resource.Resource, error) {
return res.Transform(
- &buildTransformation{rs: c.rs, sfs: c.sfs, options: options},
+ &buildTransformation{rs: c.rs, sfs: c.sfs, options: toInternalOptions(opts)},
)
}
+
+func toInternalOptions(opts Options) internalOptions {
+ target := opts.Target
+ if target == "" {
+ target = defaultTarget
+ }
+ return internalOptions{
+ TargetPath: opts.TargetPath,
+ Minify: opts.Minify,
+ Target: target,
+ Externals: opts.Externals,
+ JSXFactory: opts.JSXFactory,
+ JSXFragment: opts.JSXFragment,
+ }
+}
diff --git a/resources/resource_transformers/js/build_test.go b/resources/resource_transformers/js/build_test.go
new file mode 100644
index 000000000..3f2a1e104
--- /dev/null
+++ b/resources/resource_transformers/js/build_test.go
@@ -0,0 +1,69 @@
+// Copyright 2020 The Hugo Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package js
+
+import (
+ "testing"
+
+ qt "github.com/frankban/quicktest"
+)
+
+// This test is added to test/warn against breaking the "stability" of the
+// cache key. It's sometimes needed to break this, but should be avoided if possible.
+func TestOptionKey(t *testing.T) {
+ c := qt.New(t)
+
+ opts := internalOptions{
+ TargetPath: "foo",
+ }
+
+ key := (&buildTransformation{options: opts}).Key()
+
+ c.Assert(key.Value(), qt.Equals, "jsbuild_9405671309963492201")
+}
+
+func TestToInternalOptions(t *testing.T) {
+ c := qt.New(t)
+
+ o := Options{
+ TargetPath: "v1",
+ Target: "v2",
+ JSXFactory: "v3",
+ JSXFragment: "v4",
+ Externals: []string{"react"},
+ Minify: true,
+ }
+
+ c.Assert(toInternalOptions(o), qt.DeepEquals, internalOptions{
+ TargetPath: "v1",
+ Minify: true,
+ Target: "v2",
+ JSXFactory: "v3",
+ JSXFragment: "v4",
+ Externals: []string{"react"},
+ Defines: nil,
+ TSConfig: "",
+ })
+
+ c.Assert(toInternalOptions(Options{}), qt.DeepEquals, internalOptions{
+ TargetPath: "",
+ Minify: false,
+ Target: "esnext",
+ JSXFactory: "",
+ JSXFragment: "",
+ Externals: nil,
+ Defines: nil,
+ TSConfig: "",
+ })
+}