mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-07 20:30:36 -05:00
parent
eded9ac2a0
commit
0256959a35
5 changed files with 129 additions and 42 deletions
|
@ -45,6 +45,11 @@ defines [map]
|
||||||
{{ $defines := dict "process.env.NODE_ENV" `"development"` }}
|
{{ $defines := dict "process.env.NODE_ENV" `"development"` }}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
format [string] {{< new-in "0.75.0" >}}
|
||||||
|
: The output format.
|
||||||
|
One of: `iife`, `cjs`, `esm`.
|
||||||
|
Default is `iife`, a self-executing function, suitable for inclusion as a <script> tag.
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
|
|
||||||
```go-html-template
|
```go-html-template
|
||||||
|
|
|
@ -378,6 +378,11 @@ func DecodeTypes(mms ...map[string]interface{}) (Types, error) {
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsZero reports whether this Type represents a zero value.
|
||||||
|
func (m Type) IsZero() bool {
|
||||||
|
return m.SubType == ""
|
||||||
|
}
|
||||||
|
|
||||||
// MarshalJSON returns the JSON encoding of m.
|
// MarshalJSON returns the JSON encoding of m.
|
||||||
func (m Type) MarshalJSON() ([]byte, error) {
|
func (m Type) MarshalJSON() ([]byte, error) {
|
||||||
type Alias Type
|
type Alias Type
|
||||||
|
|
|
@ -32,6 +32,7 @@ func TestCreatePlaceholders(t *testing.T) {
|
||||||
|
|
||||||
c.Assert(m, qt.DeepEquals, map[string]interface{}{
|
c.Assert(m, qt.DeepEquals, map[string]interface{}{
|
||||||
"FullSuffix": "pre_foo.FullSuffix_post",
|
"FullSuffix": "pre_foo.FullSuffix_post",
|
||||||
|
"IsZero": "pre_foo.IsZero_post",
|
||||||
"Type": "pre_foo.Type_post",
|
"Type": "pre_foo.Type_post",
|
||||||
"MainType": "pre_foo.MainType_post",
|
"MainType": "pre_foo.MainType_post",
|
||||||
"Delimiter": "pre_foo.Delimiter_post",
|
"Delimiter": "pre_foo.Delimiter_post",
|
||||||
|
|
|
@ -33,8 +33,6 @@ import (
|
||||||
"github.com/gohugoio/hugo/resources/resource"
|
"github.com/gohugoio/hugo/resources/resource"
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultTarget = "esnext"
|
|
||||||
|
|
||||||
type Options struct {
|
type Options struct {
|
||||||
// If not set, the source path will be used as the base target path.
|
// 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
|
// Note that the target path's extension may change if the target MIME type
|
||||||
|
@ -49,6 +47,11 @@ type Options struct {
|
||||||
// Default is esnext.
|
// Default is esnext.
|
||||||
Target string
|
Target string
|
||||||
|
|
||||||
|
// The output format.
|
||||||
|
// One of: iife, cjs, esm
|
||||||
|
// Default is to esm.
|
||||||
|
Format string
|
||||||
|
|
||||||
// External dependencies, e.g. "react".
|
// External dependencies, e.g. "react".
|
||||||
Externals []string `hash:"set"`
|
Externals []string `hash:"set"`
|
||||||
|
|
||||||
|
@ -60,25 +63,29 @@ type Options struct {
|
||||||
|
|
||||||
// What to use instead of React.Fragment.
|
// What to use instead of React.Fragment.
|
||||||
JSXFragment string
|
JSXFragment string
|
||||||
|
|
||||||
|
mediaType media.Type
|
||||||
|
outDir string
|
||||||
|
contents string
|
||||||
|
sourcefile string
|
||||||
|
resolveDir string
|
||||||
}
|
}
|
||||||
|
|
||||||
func decodeOptions(m map[string]interface{}) (opts Options, err error) {
|
func decodeOptions(m map[string]interface{}) (Options, error) {
|
||||||
err = mapstructure.WeakDecode(m, &opts)
|
var opts Options
|
||||||
if err != nil {
|
|
||||||
return
|
if err := mapstructure.WeakDecode(m, &opts); err != nil {
|
||||||
|
return opts, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.TargetPath != "" {
|
if opts.TargetPath != "" {
|
||||||
opts.TargetPath = helpers.ToSlashTrimLeading(opts.TargetPath)
|
opts.TargetPath = helpers.ToSlashTrimLeading(opts.TargetPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.Target == "" {
|
|
||||||
opts.Target = defaultTarget
|
|
||||||
}
|
|
||||||
|
|
||||||
opts.Target = strings.ToLower(opts.Target)
|
opts.Target = strings.ToLower(opts.Target)
|
||||||
|
opts.Format = strings.ToLower(opts.Format)
|
||||||
|
|
||||||
return
|
return opts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
|
@ -114,9 +121,40 @@ func (t *buildTransformation) Transform(ctx *resources.ResourceTransformationCtx
|
||||||
ctx.ReplaceOutPathExtension(".js")
|
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
|
var target api.Target
|
||||||
switch opts.Target {
|
switch opts.Target {
|
||||||
case defaultTarget:
|
case "", "esnext":
|
||||||
target = api.ESNext
|
target = api.ESNext
|
||||||
case "es5":
|
case "es5":
|
||||||
target = api.ES5
|
target = api.ES5
|
||||||
|
@ -133,11 +171,17 @@ func (t *buildTransformation) Transform(ctx *resources.ResourceTransformationCtx
|
||||||
case "es2020":
|
case "es2020":
|
||||||
target = api.ES2020
|
target = api.ES2020
|
||||||
default:
|
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
|
var loader api.Loader
|
||||||
switch ctx.InMediaType.SubType {
|
switch mediaType.SubType {
|
||||||
// TODO(bep) ESBuild support a set of other loaders, but I currently fail
|
// 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.
|
// to see the relevance. That may change as we start using this.
|
||||||
case media.JavascriptType.SubType:
|
case media.JavascriptType.SubType:
|
||||||
|
@ -149,29 +193,43 @@ func (t *buildTransformation) Transform(ctx *resources.ResourceTransformationCtx
|
||||||
case media.JSXType.SubType:
|
case media.JSXType.SubType:
|
||||||
loader = api.LoaderJSX
|
loader = api.LoaderJSX
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unsupported Media Type: %q", ctx.InMediaType)
|
err = fmt.Errorf("unsupported Media Type: %q", opts.mediaType)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
src, err := ioutil.ReadAll(ctx.From)
|
var defines map[string]string
|
||||||
if err != nil {
|
if opts.Defines != nil {
|
||||||
return err
|
defines = cast.ToStringMapString(opts.Defines)
|
||||||
}
|
}
|
||||||
|
|
||||||
sdir, sfile := path.Split(ctx.SourcePath)
|
buildOptions = api.BuildOptions{
|
||||||
sdir = t.sfs.RealFilename(sdir)
|
|
||||||
|
|
||||||
buildOptions := api.BuildOptions{
|
|
||||||
Outfile: "",
|
Outfile: "",
|
||||||
Bundle: true,
|
Bundle: true,
|
||||||
|
|
||||||
Target: target,
|
Target: target,
|
||||||
|
Format: format,
|
||||||
|
|
||||||
MinifyWhitespace: opts.Minify,
|
MinifyWhitespace: opts.Minify,
|
||||||
MinifyIdentifiers: opts.Minify,
|
MinifyIdentifiers: opts.Minify,
|
||||||
MinifySyntax: opts.Minify,
|
MinifySyntax: opts.Minify,
|
||||||
|
|
||||||
Defines: cast.ToStringMapString(opts.Defines),
|
Outdir: opts.outDir,
|
||||||
|
Defines: defines,
|
||||||
|
|
||||||
Externals: opts.Externals,
|
Externals: opts.Externals,
|
||||||
|
|
||||||
|
@ -181,26 +239,12 @@ func (t *buildTransformation) Transform(ctx *resources.ResourceTransformationCtx
|
||||||
//Tsconfig: opts.TSConfig,
|
//Tsconfig: opts.TSConfig,
|
||||||
|
|
||||||
Stdin: &api.StdinOptions{
|
Stdin: &api.StdinOptions{
|
||||||
Contents: string(src),
|
Contents: opts.contents,
|
||||||
Sourcefile: sfile,
|
Sourcefile: opts.sourcefile,
|
||||||
ResolveDir: sdir,
|
ResolveDir: opts.resolveDir,
|
||||||
Loader: loader,
|
Loader: loader,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
result := api.Build(buildOptions)
|
return
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
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},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,10 @@ package js
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/media"
|
||||||
|
|
||||||
|
"github.com/evanw/esbuild/pkg/api"
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -26,9 +30,37 @@ func TestOptionKey(t *testing.T) {
|
||||||
|
|
||||||
opts := map[string]interface{}{
|
opts := map[string]interface{}{
|
||||||
"TargetPath": "foo",
|
"TargetPath": "foo",
|
||||||
|
"Target": "es2018",
|
||||||
}
|
}
|
||||||
|
|
||||||
key := (&buildTransformation{optsm: opts}).Key()
|
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{},
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue