summaryrefslogtreecommitdiffstats
path: root/tpl
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2024-06-23 12:10:35 +0200
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2024-06-25 15:48:02 +0200
commiteddcd2bac6bfd3cc0ac1a3b38bf8c4ae452ea23b (patch)
tree10116d4362d0a9dae56539cc8f9d852c2a4a66ce /tpl
parent1687a9a5852e83a1c52e647e92882d9e6bfc109a (diff)
Clean up the css related template funcs package structure
Deprecate and move: * resources.ToCSS => css.SASS * resources.PostProcess => css.PostProcess * resources.Babel => js.Babel Updates #12618
Diffstat (limited to 'tpl')
-rw-r--r--tpl/css/css.go145
-rw-r--r--tpl/internal/templatefuncsRegistry.go3
-rw-r--r--tpl/js/init.go5
-rw-r--r--tpl/js/js.go30
-rw-r--r--tpl/resources/init.go33
-rw-r--r--tpl/resources/resources.go171
-rw-r--r--tpl/tplimpl/template_funcs.go16
7 files changed, 241 insertions, 162 deletions
diff --git a/tpl/css/css.go b/tpl/css/css.go
index 51fa1d518..145cb3aad 100644
--- a/tpl/css/css.go
+++ b/tpl/css/css.go
@@ -2,17 +2,40 @@ package css
import (
"context"
+ "errors"
+ "fmt"
+ "sync"
+ "github.com/gohugoio/hugo/common/maps"
+ "github.com/gohugoio/hugo/common/paths"
"github.com/gohugoio/hugo/common/types/css"
"github.com/gohugoio/hugo/deps"
+ "github.com/gohugoio/hugo/resources"
+ "github.com/gohugoio/hugo/resources/resource"
+ "github.com/gohugoio/hugo/resources/resource_transformers/babel"
+ "github.com/gohugoio/hugo/resources/resource_transformers/postcss"
+ "github.com/gohugoio/hugo/resources/resource_transformers/tocss/dartsass"
+ "github.com/gohugoio/hugo/resources/resource_transformers/tocss/scss"
"github.com/gohugoio/hugo/tpl/internal"
+ "github.com/gohugoio/hugo/tpl/internal/resourcehelpers"
"github.com/spf13/cast"
)
const name = "css"
// Namespace provides template functions for the "css" namespace.
-type Namespace struct{}
+type Namespace struct {
+ d *deps.Deps
+ scssClientLibSass *scss.Client
+ postcssClient *postcss.Client
+ babelClient *babel.Client
+
+ // The Dart Client requires a os/exec process, so only
+ // create it if we really need it.
+ // This is mostly to avoid creating one per site build test.
+ scssClientDartSassInit sync.Once
+ scssClientDartSass *dartsass.Client
+}
// Quoted returns a string that needs to be quoted in CSS.
func (ns *Namespace) Quoted(v any) css.QuotedString {
@@ -26,17 +49,135 @@ func (ns *Namespace) Unquoted(v any) css.UnquotedString {
return css.UnquotedString(s)
}
+// PostCSS processes the given Resource with PostCSS.
+func (ns *Namespace) PostCSS(args ...any) (resource.Resource, error) {
+ if len(args) > 2 {
+ return nil, errors.New("must not provide more arguments than resource object and options")
+ }
+
+ r, m, err := resourcehelpers.ResolveArgs(args)
+ if err != nil {
+ return nil, err
+ }
+
+ return ns.postcssClient.Process(r, m)
+}
+
+// Sass processes the given Resource with Sass.
+func (ns *Namespace) Sass(args ...any) (resource.Resource, error) {
+ if len(args) > 2 {
+ return nil, errors.New("must not provide more arguments than resource object and options")
+ }
+
+ const (
+ // Transpiler implementation can be controlled from the client by
+ // setting the 'transpiler' option.
+ // Default is currently 'libsass', but that may change.
+ transpilerDart = "dartsass"
+ transpilerLibSass = "libsass"
+ )
+
+ var (
+ r resources.ResourceTransformer
+ m map[string]any
+ targetPath string
+ err error
+ ok bool
+ transpiler = transpilerLibSass
+ )
+
+ r, targetPath, ok = resourcehelpers.ResolveIfFirstArgIsString(args)
+
+ if !ok {
+ r, m, err = resourcehelpers.ResolveArgs(args)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ if m != nil {
+ if t, _, found := maps.LookupEqualFold(m, "transpiler"); found {
+ switch t {
+ case transpilerDart, transpilerLibSass:
+ transpiler = cast.ToString(t)
+ default:
+ return nil, fmt.Errorf("unsupported transpiler %q; valid values are %q or %q", t, transpilerLibSass, transpilerDart)
+ }
+ }
+ }
+
+ if transpiler == transpilerLibSass {
+ var options scss.Options
+ if targetPath != "" {
+ options.TargetPath = paths.ToSlashTrimLeading(targetPath)
+ } else if m != nil {
+ options, err = scss.DecodeOptions(m)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return ns.scssClientLibSass.ToCSS(r, options)
+ }
+
+ if m == nil {
+ m = make(map[string]any)
+ }
+ if targetPath != "" {
+ m["targetPath"] = targetPath
+ }
+
+ client, err := ns.getscssClientDartSass()
+ if err != nil {
+ return nil, err
+ }
+
+ return client.ToCSS(r, m)
+}
+
func init() {
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
- ctx := &Namespace{}
+ scssClient, err := scss.New(d.BaseFs.Assets, d.ResourceSpec)
+ if err != nil {
+ panic(err)
+ }
+ ctx := &Namespace{
+ d: d,
+ scssClientLibSass: scssClient,
+ postcssClient: postcss.New(d.ResourceSpec),
+ babelClient: babel.New(d.ResourceSpec),
+ }
ns := &internal.TemplateFuncsNamespace{
Name: name,
Context: func(cctx context.Context, args ...any) (any, error) { return ctx, nil },
}
+ ns.AddMethodMapping(ctx.Sass,
+ []string{"toCSS"},
+ [][2]string{},
+ )
+
+ ns.AddMethodMapping(ctx.PostCSS,
+ []string{"postCSS"},
+ [][2]string{},
+ )
+
return ns
}
internal.AddTemplateFuncsNamespace(f)
}
+
+func (ns *Namespace) getscssClientDartSass() (*dartsass.Client, error) {
+ var err error
+ ns.scssClientDartSassInit.Do(func() {
+ ns.scssClientDartSass, err = dartsass.New(ns.d.BaseFs.Assets, ns.d.ResourceSpec)
+ if err != nil {
+ return
+ }
+ ns.d.BuildClosers.Add(ns.scssClientDartSass)
+ })
+
+ return ns.scssClientDartSass, err
+}
diff --git a/tpl/internal/templatefuncsRegistry.go b/tpl/internal/templatefuncsRegistry.go
index fc02a6ef9..1b74bf443 100644
--- a/tpl/internal/templatefuncsRegistry.go
+++ b/tpl/internal/templatefuncsRegistry.go
@@ -51,6 +51,9 @@ type TemplateFuncsNamespace struct {
// This is the method receiver.
Context func(ctx context.Context, v ...any) (any, error)
+ // OnCreated is called when all the namespaces are ready.
+ OnCreated func(namespaces map[string]any)
+
// Additional info, aliases and examples, per method name.
MethodMappings map[string]TemplateFuncMethodMapping
}
diff --git a/tpl/js/init.go b/tpl/js/init.go
index 16e6c7efa..69d7c7275 100644
--- a/tpl/js/init.go
+++ b/tpl/js/init.go
@@ -31,6 +31,11 @@ func init() {
Context: func(cctx context.Context, args ...any) (any, error) { return ctx, nil },
}
+ ns.AddMethodMapping(ctx.Babel,
+ []string{"babel"},
+ [][2]string{},
+ )
+
return ns
}
diff --git a/tpl/js/js.go b/tpl/js/js.go
index 63a676532..c68e0af92 100644
--- a/tpl/js/js.go
+++ b/tpl/js/js.go
@@ -15,9 +15,12 @@
package js
import (
+ "errors"
+
"github.com/gohugoio/hugo/deps"
"github.com/gohugoio/hugo/resources"
"github.com/gohugoio/hugo/resources/resource"
+ "github.com/gohugoio/hugo/resources/resource_transformers/babel"
"github.com/gohugoio/hugo/resources/resource_transformers/js"
"github.com/gohugoio/hugo/tpl/internal/resourcehelpers"
)
@@ -28,13 +31,15 @@ func New(deps *deps.Deps) *Namespace {
return &Namespace{}
}
return &Namespace{
- client: js.New(deps.BaseFs.Assets, deps.ResourceSpec),
+ client: js.New(deps.BaseFs.Assets, deps.ResourceSpec),
+ babelClient: babel.New(deps.ResourceSpec),
}
}
// Namespace provides template functions for the "js" namespace.
type Namespace struct {
- client *js.Client
+ client *js.Client
+ babelClient *babel.Client
}
// Build processes the given Resource with ESBuild.
@@ -62,3 +67,24 @@ func (ns *Namespace) Build(args ...any) (resource.Resource, error) {
return ns.client.Process(r, m)
}
+
+// Babel processes the given Resource with Babel.
+func (ns *Namespace) Babel(args ...any) (resource.Resource, error) {
+ if len(args) > 2 {
+ return nil, errors.New("must not provide more arguments than resource object and options")
+ }
+
+ r, m, err := resourcehelpers.ResolveArgs(args)
+ if err != nil {
+ return nil, err
+ }
+ var options babel.Options
+ if m != nil {
+ options, err = babel.DecodeOptions(m)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return ns.babelClient.Process(r, options)
+}
diff --git a/tpl/resources/init.go b/tpl/resources/init.go
index db51b0287..5cea482ac 100644
--- a/tpl/resources/init.go
+++ b/tpl/resources/init.go
@@ -17,7 +17,9 @@ import (
"context"
"github.com/gohugoio/hugo/deps"
+ "github.com/gohugoio/hugo/tpl/css"
"github.com/gohugoio/hugo/tpl/internal"
+ "github.com/gohugoio/hugo/tpl/js"
)
const name = "resources"
@@ -33,6 +35,22 @@ func init() {
ns := &internal.TemplateFuncsNamespace{
Name: name,
Context: func(cctx context.Context, args ...any) (any, error) { return ctx, nil },
+ OnCreated: func(m map[string]any) {
+ for _, v := range m {
+ switch v := v.(type) {
+ case *css.Namespace:
+ ctx.cssNs = v
+ case *js.Namespace:
+ ctx.jsNs = v
+ }
+ }
+ if ctx.cssNs == nil {
+ panic("css namespace not found")
+ }
+ if ctx.jsNs == nil {
+ panic("js namespace not found")
+ }
+ },
}
ns.AddMethodMapping(ctx.Get,
@@ -57,21 +75,6 @@ func init() {
[][2]string{},
)
- ns.AddMethodMapping(ctx.ToCSS,
- []string{"toCSS"},
- [][2]string{},
- )
-
- ns.AddMethodMapping(ctx.PostCSS,
- []string{"postCSS"},
- [][2]string{},
- )
-
- ns.AddMethodMapping(ctx.Babel,
- []string{"babel"},
- [][2]string{},
- )
-
return ns
}
diff --git a/tpl/resources/resources.go b/tpl/resources/resources.go
index 34b4464be..78340b1ff 100644
--- a/tpl/resources/resources.go
+++ b/tpl/resources/resources.go
@@ -18,12 +18,12 @@ import (
"context"
"errors"
"fmt"
- "sync"
+ "github.com/gohugoio/hugo/common/hugo"
"github.com/gohugoio/hugo/common/maps"
- "github.com/gohugoio/hugo/common/paths"
- "github.com/gohugoio/hugo/tpl/internal/resourcehelpers"
+ "github.com/gohugoio/hugo/tpl/css"
+ "github.com/gohugoio/hugo/tpl/js"
"github.com/gohugoio/hugo/resources/postpub"
@@ -33,13 +33,9 @@ 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/dartsass"
- "github.com/gohugoio/hugo/resources/resource_transformers/tocss/scss"
"github.com/spf13/cast"
)
@@ -50,26 +46,18 @@ func New(deps *deps.Deps) (*Namespace, error) {
return &Namespace{}, nil
}
- scssClient, err := scss.New(deps.BaseFs.Assets, deps.ResourceSpec)
- if err != nil {
- return nil, err
- }
-
minifyClient, err := minifier.New(deps.ResourceSpec)
if err != nil {
return nil, err
}
return &Namespace{
- deps: deps,
- scssClientLibSass: 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),
+ deps: deps,
+ createClient: create.New(deps.ResourceSpec),
+ bundlerClient: bundler.New(deps.ResourceSpec),
+ integrityClient: integrity.New(deps.ResourceSpec),
+ minifyClient: minifyClient,
+ templatesClient: templates.New(deps.ResourceSpec, deps),
}, nil
}
@@ -79,33 +67,16 @@ var _ resource.ResourceFinder = (*Namespace)(nil)
type Namespace struct {
deps *deps.Deps
- createClient *create.Client
- bundlerClient *bundler.Client
- scssClientLibSass *scss.Client
- integrityClient *integrity.Client
- minifyClient *minifier.Client
- postcssClient *postcss.Client
- babelClient *babel.Client
- templatesClient *templates.Client
-
- // The Dart Client requires a os/exec process, so only
- // create it if we really need it.
- // This is mostly to avoid creating one per site build test.
- scssClientDartSassInit sync.Once
- scssClientDartSass *dartsass.Client
-}
-
-func (ns *Namespace) getscssClientDartSass() (*dartsass.Client, error) {
- var err error
- ns.scssClientDartSassInit.Do(func() {
- ns.scssClientDartSass, err = dartsass.New(ns.deps.BaseFs.Assets, ns.deps.ResourceSpec)
- if err != nil {
- return
- }
- ns.deps.BuildClosers.Add(ns.scssClientDartSass)
- })
+ createClient *create.Client
+ bundlerClient *bundler.Client
+ integrityClient *integrity.Client
+ minifyClient *minifier.Client
+ templatesClient *templates.Client
- return ns.scssClientDartSass, err
+ // We moved some CSS and JS related functions to the css and js package in Hugo 0.128.0.
+ // Keep this here until the deprecation period is over.
+ cssNs *css.Namespace
+ jsNs *js.Namespace
}
// Copy copies r to the new targetPath in s.
@@ -337,89 +308,17 @@ func (ns *Namespace) Minify(r resources.ResourceTransformer) (resource.Resource,
// ToCSS converts the given Resource to CSS. You can optional provide an Options object
// as second argument. As an option, you can e.g. specify e.g. the target path (string)
// for the converted CSS resource.
+// Deprecated: Moved to the css namespace in Hugo 0.128.0.
func (ns *Namespace) ToCSS(args ...any) (resource.Resource, error) {
- if len(args) > 2 {
- return nil, errors.New("must not provide more arguments than resource object and options")
- }
-
- const (
- // Transpiler implementation can be controlled from the client by
- // setting the 'transpiler' option.
- // Default is currently 'libsass', but that may change.
- transpilerDart = "dartsass"
- transpilerLibSass = "libsass"
- )
-
- var (
- r resources.ResourceTransformer
- m map[string]any
- targetPath string
- err error
- ok bool
- transpiler = transpilerLibSass
- )
-
- r, targetPath, ok = resourcehelpers.ResolveIfFirstArgIsString(args)
-
- if !ok {
- r, m, err = resourcehelpers.ResolveArgs(args)
- if err != nil {
- return nil, err
- }
- }
-
- if m != nil {
- if t, _, found := maps.LookupEqualFold(m, "transpiler"); found {
- switch t {
- case transpilerDart, transpilerLibSass:
- transpiler = cast.ToString(t)
- default:
- return nil, fmt.Errorf("unsupported transpiler %q; valid values are %q or %q", t, transpilerLibSass, transpilerDart)
- }
- }
- }
-
- if transpiler == transpilerLibSass {
- var options scss.Options
- if targetPath != "" {
- options.TargetPath = paths.ToSlashTrimLeading(targetPath)
- } else if m != nil {
- options, err = scss.DecodeOptions(m)
- if err != nil {
- return nil, err
- }
- }
-
- return ns.scssClientLibSass.ToCSS(r, options)
- }
-
- if m == nil {
- m = make(map[string]any)
- }
- if targetPath != "" {
- m["targetPath"] = targetPath
- }
-
- client, err := ns.getscssClientDartSass()
- if err != nil {
- return nil, err
- }
-
- return client.ToCSS(r, m)
+ hugo.Deprecate("resources.ToCSS", "Use css.SASS.", "v0.128.0")
+ return ns.cssNs.Sass(args...)
}
-// PostCSS processes the given Resource with PostCSS
+// PostCSS processes the given Resource with PostCSS.
+// Deprecated: Moved to the css namespace in Hugo 0.128.0.
func (ns *Namespace) PostCSS(args ...any) (resource.Resource, error) {
- if len(args) > 2 {
- return nil, errors.New("must not provide more arguments than resource object and options")
- }
-
- r, m, err := resourcehelpers.ResolveArgs(args)
- if err != nil {
- return nil, err
- }
-
- return ns.postcssClient.Process(r, m)
+ hugo.Deprecate("resources.PostCSS", "Use css.PostCSS.", "v0.128.0")
+ return ns.cssNs.PostCSS(args...)
}
// PostProcess processes r after the build.
@@ -428,22 +327,8 @@ func (ns *Namespace) PostProcess(r resource.Resource) (postpub.PostPublishedReso
}
// Babel processes the given Resource with Babel.
+// Deprecated: Moved to the js namespace in Hugo 0.128.0.
func (ns *Namespace) Babel(args ...any) (resource.Resource, error) {
- if len(args) > 2 {
- return nil, errors.New("must not provide more arguments than resource object and options")
- }
-
- r, m, err := resourcehelpers.ResolveArgs(args)
- if err != nil {
- return nil, err
- }
- var options babel.Options
- if m != nil {
- options, err = babel.DecodeOptions(m)
- if err != nil {
- return nil, err
- }
- }
-
- return ns.babelClient.Process(r, options)
+ hugo.Deprecate("resources.Babel", "Use js.Babel.", "v0.128.0")
+ return ns.jsNs.Babel(args...)
}
diff --git a/tpl/tplimpl/template_funcs.go b/tpl/tplimpl/template_funcs.go
index e5ee4d54f..815270631 100644
--- a/tpl/tplimpl/template_funcs.go
+++ b/tpl/tplimpl/template_funcs.go
@@ -252,6 +252,9 @@ func newTemplateExecuter(d *deps.Deps) (texttemplate.Executer, map[string]reflec
func createFuncMap(d *deps.Deps) map[string]any {
funcMap := template.FuncMap{}
+ nsMap := make(map[string]any)
+ var onCreated []func(namespaces map[string]any)
+
// Merge the namespace funcs
for _, nsf := range internal.TemplateFuncsNamespaceRegistry {
ns := nsf(d)
@@ -259,6 +262,11 @@ func createFuncMap(d *deps.Deps) map[string]any {
panic(ns.Name + " is a duplicate template func")
}
funcMap[ns.Name] = ns.Context
+ contextV, err := ns.Context(context.Background())
+ if err != nil {
+ panic(err)
+ }
+ nsMap[ns.Name] = contextV
for _, mm := range ns.MethodMappings {
for _, alias := range mm.Aliases {
if _, exists := funcMap[alias]; exists {
@@ -267,6 +275,14 @@ func createFuncMap(d *deps.Deps) map[string]any {
funcMap[alias] = mm.Method
}
}
+
+ if ns.OnCreated != nil {
+ onCreated = append(onCreated, ns.OnCreated)
+ }
+ }
+
+ for _, f := range onCreated {
+ f(nsMap)
}
if d.OverloadedTemplateFuncs != nil {