Rename transpileJS to babel

And add a test.

Updates #5764
This commit is contained in:
Bjørn Erik Pedersen 2020-04-28 14:02:41 +02:00
parent 2a171ff1c5
commit 6add6d77b4
8 changed files with 233 additions and 119 deletions

View file

@ -16,6 +16,9 @@ package hugo
import (
"fmt"
"html/template"
"os"
"github.com/gohugoio/hugo/config"
)
const (
@ -69,3 +72,9 @@ func NewInfo(environment string) Info {
Environment: environment,
}
}
func GetExecEnviron(cfg config.Provider) []string {
env := os.Environ()
config.SetEnvVars(&env, "HUGO_ENVIRONMENT", cfg.GetString("environment"))
return env
}

View file

@ -0,0 +1,55 @@
---
title: Babel
description: Hugo Pipes can process JS files with Babel.
date: 2019-03-21
publishdate: 2019-03-21
lastmod: 2019-03-21
categories: [asset management]
keywords: []
menu:
docs:
parent: "pipes"
weight: 49
weight: 49
sections_weight: 49
draft: false
---
Any JavaScript resource file can be transpiled to another JavaScript version using `resources.Babel` which takes for argument the resource object and an optional dict of options listed below. Babel uses the [babel cli](https://babeljs.io/docs/en/babel-cli).
{{% note %}}
Hugo Pipe's Babel requires the `@babel/cli` and `@babel/core` JavaScript packages to be installed in the project or globally (`npm install -g @babel/cli @babel/core`) along with any Babel plugin(s) or preset(s) used (e.g., `npm install @babel/preset-env --save-dev`).
If you are using the Hugo Snap package, Babel and plugin(s) need to be installed locally within your Hugo site directory, e.g., `npm install @babel/cli @babel/core --save-dev` without the `-g` flag.
{{% /note %}}
### Options
config [string]
: Path to the Babel configuration file. Hugo will, by default, look for a `babel.config.js` in your project. More information on these configuration files can be found here: [babel configuration](https://babeljs.io/docs/en/configuration).
minified [bool]
: Save as much bytes as possible when printing
noComments [bool]
: Write comments to generated output (true by default)
compact [bool]
: Do not include superfluous whitespace characters and line terminators. Defaults to `auto` if not set.
verbose [bool]
: Log everything
### Examples
```go-html-template
{{- $transpiled := resources.Get "scripts/main.js" | babel -}}
```
Or with options:
```go-html-template
{{ $opts := dict "noComments" true }}
{{- $transpiled := resources.Get "scripts/main.js" | babel $opts -}}
```

View file

@ -1,69 +0,0 @@
---
title: TransformJS
description: Hugo Pipes can process JS files with Babel.
date: 2019-03-21
publishdate: 2019-03-21
lastmod: 2019-03-21
categories: [asset management]
keywords: []
menu:
docs:
parent: "pipes"
weight: 75
weight: 75
sections_weight: 75
draft: false
---
Any JavaScript resource file can be transpiled to another JavaScript version using `resources.TransformJS` which takes for argument the resource object and a slice of options listed below. TransformJS uses the [babel cli](https://babeljs.io/docs/en/babel-cli).
{{% note %}}
Hugo Pipe's TranspileJS requires the `@babel/cli` and `@babel/core` JavaScript packages to be installed in the environment (`npm install -g @babel/cli @babel/core`) along with any Babel plugin(s) or preset(s) used (e.g., `npm install -g @babel/preset-env`).
If you are using the Hugo Snap package, Babel and plugin(s) need to be installed locally within your Hugo site directory, e.g., `npm install @babel/cli @babel/core` without the `-g` flag.
{{% /note %}}
### Options
config [string]
: Path to the Babel configuration file
_If no configuration file is used:_
plugins [string]
: Comma seperated string of Babel plugins to use
presets [string]
: Comma seperated string of Babel presets to use
minified [bool]
: Save as much bytes as possible when printing
noComments [bool]
: Write comments to generated output (true by default)
compact [string]
: Do not include superfluous whitespace characters and line terminators (true/false/auto)
verbose [bool]
: Log everything
### Examples
Without a `.babelrc` file, you can simply pass the options like so:
```go-html-template
{{- $transpileOpts := (dict "presets" "@babel/preset-env" "minified" true "noComments" true "compact" "true" ) -}}
{{- $transpiled := resources.Get "scripts/main.js" | transpileJS $transpileOpts -}}
```
If you rather want to use a config file, you can leave out the options in the template.
```go-html-template
{{- $transpiled := resources.Get "scripts/main.js" | transpileJS $transpileOpts -}}
```
Then, you can either create a `.babelrc` in the root of your project, or your can create a `.babel.config.js`.
More information on these configuration files can be found here: [babel configuration](https://babeljs.io/docs/en/configuration)
Finally, you can also pass a custom file path to a config file like so:
```go-html-template
{{- $transpileOpts := (dict "config" "config/my-babel-config.js" ) -}}
{{- $transpiled := resources.Get "scripts/main.js" | transpileJS $transpileOpts -}}
```

View file

@ -0,0 +1,127 @@
// 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 hugolib
import (
"os"
"os/exec"
"path/filepath"
"runtime"
"testing"
"github.com/gohugoio/hugo/htesting"
"github.com/spf13/viper"
qt "github.com/frankban/quicktest"
"github.com/gohugoio/hugo/hugofs"
"github.com/gohugoio/hugo/common/loggers"
)
func TestResourceChainBabel(t *testing.T) {
if !isCI() {
t.Skip("skip (relative) long running modules test when running locally")
}
if runtime.GOOS == "windows" {
t.Skip("skip npm test on Windows")
}
wd, _ := os.Getwd()
defer func() {
os.Chdir(wd)
}()
c := qt.New(t)
packageJSON := `{
"scripts": {},
"devDependencies": {
"@babel/cli": "7.8.4",
"@babel/core": "7.9.0",
"@babel/preset-env": "7.9.5"
}
}
`
babelConfig := `
console.error("Hugo Environment:", process.env.HUGO_ENVIRONMENT );
module.exports = {
presets: ["@babel/preset-env"],
};
`
js := `
/* A Car */
class Car {
constructor(brand) {
this.carname = brand;
}
}
`
workDir, clean, err := htesting.CreateTempDir(hugofs.Os, "hugo-test-babel")
c.Assert(err, qt.IsNil)
defer clean()
v := viper.New()
v.Set("workingDir", workDir)
v.Set("disableKinds", []string{"taxonomyTerm", "taxonomy", "page"})
b := newTestSitesBuilder(t).WithLogger(loggers.NewWarningLogger())
// Need to use OS fs for this.
b.Fs = hugofs.NewDefault(v)
b.WithWorkingDir(workDir)
b.WithViper(v)
b.WithContent("p1.md", "")
b.WithTemplates("index.html", `
{{ $options := dict "noComments" true }}
{{ $transpiled := resources.Get "js/main.js" | babel -}}
Transpiled: {{ $transpiled.Content | safeJS }}
`)
jsDir := filepath.Join(workDir, "assets", "js")
b.Assert(os.MkdirAll(jsDir, 0777), qt.IsNil)
b.WithSourceFile("assets/js/main.js", js)
b.WithSourceFile("package.json", packageJSON)
b.WithSourceFile("babel.config.js", babelConfig)
b.Assert(os.Chdir(workDir), qt.IsNil)
_, err = exec.Command("npm", "install").CombinedOutput()
b.Assert(err, qt.IsNil)
out, err := captureStderr(func() error {
return b.BuildE(BuildCfg{})
})
// Make sure Node sees this.
b.Assert(out, qt.Contains, "Hugo Environment: production")
b.Assert(err, qt.IsNil)
b.AssertFileContent("public/index.html", `
var Car = function Car(brand) {
_classCallCheck(this, Car);
this.carname = brand;
};
`)
}

View file

@ -1,4 +1,4 @@
// Copyright 2018 The Hugo Authors. All rights reserved.
// 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.
@ -11,14 +11,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package transpilejs
package babel
import (
"io"
"os"
"os/exec"
"path/filepath"
"strconv"
"github.com/gohugoio/hugo/common/hugo"
"github.com/gohugoio/hugo/resources/internal"
"github.com/mitchellh/mapstructure"
@ -32,14 +34,13 @@ import (
// Options from https://babeljs.io/docs/en/options
type Options struct {
Config string //Custom path to config file
Plugins string //Comma seperated string of plugins
Presets string //Comma seperated string of presets
Minified bool //true/false
NoComments bool //true/false
Compact string //true/false/auto
Verbose bool //true/false
NoBabelrc bool //true/false
Config string // Custom path to config file
Minified bool
NoComments bool
Compact *bool
Verbose bool
NoBabelrc bool
}
func DecodeOptions(m map[string]interface{}) (opts Options, err error) {
@ -52,20 +53,14 @@ func DecodeOptions(m map[string]interface{}) (opts Options, err error) {
func (opts Options) toArgs() []string {
var args []string
if opts.Plugins != "" {
args = append(args, "--plugins="+opts.Plugins)
}
if opts.Presets != "" {
args = append(args, "--presets="+opts.Presets)
}
if opts.Minified {
args = append(args, "--minified")
}
if opts.NoComments {
args = append(args, "--no-comments")
}
if opts.Compact != "" {
args = append(args, "--compact="+opts.Compact)
if opts.Compact != nil {
args = append(args, "--compact="+strconv.FormatBool(*opts.Compact))
}
if opts.Verbose {
args = append(args, "--verbose")
@ -103,7 +98,6 @@ func (t *babelTransformation) Key() internal.ResourceTransformationKey {
// npm install -g @babel/preset-env
// Instead of installing globally, you can also install everything as a dev-dependency (--save-dev instead of -g)
func (t *babelTransformation) Transform(ctx *resources.ResourceTransformationCtx) error {
const localBabelPath = "node_modules/@babel/cli/bin/"
const binaryName = "babel.js"
@ -164,6 +158,7 @@ func (t *babelTransformation) Transform(ctx *resources.ResourceTransformationCtx
cmd.Stdout = ctx.To
cmd.Stderr = os.Stderr
cmd.Env = hugo.GetExecEnviron(t.rs.Cfg)
stdin, err := cmd.StdinPipe()
if err != nil {

View file

@ -25,9 +25,9 @@ import (
"strconv"
"strings"
"github.com/gohugoio/hugo/common/loggers"
"github.com/gohugoio/hugo/common/hugo"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/common/loggers"
"github.com/gohugoio/hugo/resources/internal"
"github.com/spf13/afero"
@ -202,10 +202,7 @@ func (t *postcssTransformation) Transform(ctx *resources.ResourceTransformationC
cmd.Stdout = ctx.To
cmd.Stderr = io.MultiWriter(os.Stderr, &errBuf)
// TODO(bep) somehow generalize this to other external helpers that may need this.
env := os.Environ()
config.SetEnvVars(&env, "HUGO_ENVIRONMENT", t.rs.Cfg.GetString("environment"))
cmd.Env = env
cmd.Env = hugo.GetExecEnviron(t.rs.Cfg)
stdin, err := cmd.StdinPipe()
if err != nil {

View file

@ -60,8 +60,8 @@ func init() {
[][2]string{},
)
ns.AddMethodMapping(ctx.TranspileJS,
[]string{"transpileJS"},
ns.AddMethodMapping(ctx.Babel,
[]string{"babel"},
[][2]string{},
)

View file

@ -29,12 +29,12 @@ import (
"github.com/gohugoio/hugo/resources/resource_factories/bundler"
"github.com/gohugoio/hugo/resources/resource_factories/create"
"github.com/gohugoio/hugo/resources/resource_transformers/babel"
"github.com/gohugoio/hugo/resources/resource_transformers/integrity"
"github.com/gohugoio/hugo/resources/resource_transformers/minifier"
"github.com/gohugoio/hugo/resources/resource_transformers/postcss"
"github.com/gohugoio/hugo/resources/resource_transformers/templates"
"github.com/gohugoio/hugo/resources/resource_transformers/tocss/scss"
"github.com/gohugoio/hugo/resources/resource_transformers/transpilejs"
"github.com/spf13/cast"
)
@ -55,15 +55,15 @@ func New(deps *deps.Deps) (*Namespace, error) {
}
return &Namespace{
deps: deps,
scssClient: scssClient,
createClient: create.New(deps.ResourceSpec),
bundlerClient: bundler.New(deps.ResourceSpec),
integrityClient: integrity.New(deps.ResourceSpec),
minifyClient: minifyClient,
postcssClient: postcss.New(deps.ResourceSpec),
templatesClient: templates.New(deps.ResourceSpec, deps),
transpileJSClient: transpilejs.New(deps.ResourceSpec),
deps: deps,
scssClient: scssClient,
createClient: create.New(deps.ResourceSpec),
bundlerClient: bundler.New(deps.ResourceSpec),
integrityClient: integrity.New(deps.ResourceSpec),
minifyClient: minifyClient,
postcssClient: postcss.New(deps.ResourceSpec),
templatesClient: templates.New(deps.ResourceSpec, deps),
babelClient: babel.New(deps.ResourceSpec),
}, nil
}
@ -71,14 +71,14 @@ func New(deps *deps.Deps) (*Namespace, error) {
type Namespace struct {
deps *deps.Deps
createClient *create.Client
bundlerClient *bundler.Client
scssClient *scss.Client
integrityClient *integrity.Client
minifyClient *minifier.Client
postcssClient *postcss.Client
transpileJSClient *transpilejs.Client
templatesClient *templates.Client
createClient *create.Client
bundlerClient *bundler.Client
scssClient *scss.Client
integrityClient *integrity.Client
minifyClient *minifier.Client
postcssClient *postcss.Client
babelClient *babel.Client
templatesClient *templates.Client
}
// Get locates the filename given in Hugo's assets filesystem
@ -283,22 +283,22 @@ func (ns *Namespace) PostProcess(r resource.Resource) (postpub.PostPublishedReso
}
// TranspileJS processes the given Resource with Babel.
func (ns *Namespace) TranspileJS(args ...interface{}) (resource.Resource, error) {
// Babel processes the given Resource with Babel.
func (ns *Namespace) Babel(args ...interface{}) (resource.Resource, error) {
r, m, err := ns.resolveArgs(args)
if err != nil {
return nil, err
}
var options transpilejs.Options
var options babel.Options
if m != nil {
options, err = transpilejs.DecodeOptions(m)
options, err = babel.DecodeOptions(m)
if err != nil {
return nil, err
}
}
return ns.transpileJSClient.Process(r, options)
return ns.babelClient.Process(r, options)
}