Skip to content

Commit 55f4c21

Browse files
committed
Add js.Bundle
Fixes gohugoio#12626
1 parent 28f621d commit 55f4c21

File tree

11 files changed

+1158
-133
lines changed

11 files changed

+1158
-133
lines changed

common/maps/scratch.go

+14
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,20 @@ func (c *Scratch) Get(key string) any {
107107
return val
108108
}
109109

110+
// GetOrCreate returns the value for the given key if it exists, or creates it
111+
// using the given func and stores that value in the map.
112+
// For internal use.
113+
func (c *Scratch) GetOrCreate(key string, create func() any) any {
114+
c.mu.Lock()
115+
defer c.mu.Unlock()
116+
if val, found := c.values[key]; found {
117+
return val
118+
}
119+
val := create()
120+
c.values[key] = val
121+
return val
122+
}
123+
110124
// Values returns the raw backing map. Note that you should just use
111125
// this method on the locally scoped Scratch instances you obtain via newScratch, not
112126
// .Page.Scratch etc., as that will lead to concurrency issues.

resources/resource_transformers/js/build.go

+56-61
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2020 The Hugo Authors. All rights reserved.
1+
// Copyright 2024 The Hugo Authors. All rights reserved.
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.
@@ -16,25 +16,20 @@ package js
1616
import (
1717
"errors"
1818
"fmt"
19-
"io"
2019
"os"
2120
"path"
2221
"path/filepath"
2322
"regexp"
2423
"strings"
2524

26-
"github.com/spf13/afero"
27-
28-
"github.com/gohugoio/hugo/hugofs"
29-
"github.com/gohugoio/hugo/media"
30-
25+
"github.com/evanw/esbuild/pkg/api"
3126
"github.com/gohugoio/hugo/common/herrors"
3227
"github.com/gohugoio/hugo/common/text"
33-
28+
"github.com/gohugoio/hugo/hugofs"
3429
"github.com/gohugoio/hugo/hugolib/filesystems"
35-
"github.com/gohugoio/hugo/resources/internal"
30+
"github.com/gohugoio/hugo/identity"
31+
"github.com/spf13/afero"
3632

37-
"github.com/evanw/esbuild/pkg/api"
3833
"github.com/gohugoio/hugo/resources"
3934
"github.com/gohugoio/hugo/resources/resource"
4035
)
@@ -53,46 +48,47 @@ func New(fs *filesystems.SourceFilesystem, rs *resources.Spec) *Client {
5348
}
5449
}
5550

56-
type buildTransformation struct {
57-
optsm map[string]any
58-
c *Client
51+
// ProcessExernal processes a resource with the user provided options.
52+
func (c *Client) ProcessExernal(res resources.ResourceTransformer, opts map[string]any) (resource.Resource, error) {
53+
return res.Transform(
54+
&buildTransformation{c: c, optsm: opts},
55+
)
5956
}
6057

61-
func (t *buildTransformation) Key() internal.ResourceTransformationKey {
62-
return internal.NewResourceTransformationKey("jsbuild", t.optsm)
58+
// ProcessExernal processes a resource with the given options.
59+
func (c *Client) ProcessInternal(res resources.ResourceTransformer, opts Options) (resource.Resource, error) {
60+
return res.Transform(
61+
&buildTransformation{c: c, opts: opts},
62+
)
6363
}
6464

65-
func (t *buildTransformation) Transform(ctx *resources.ResourceTransformationCtx) error {
66-
ctx.OutMediaType = media.Builtin.JavascriptType
65+
func (c *Client) BuildBundle(opts Options) error {
66+
return c.build(opts, nil)
67+
}
6768

68-
opts, err := decodeOptions(t.optsm)
69-
if err != nil {
70-
return err
69+
// Note that transformCtx may be nil.
70+
func (c *Client) build(opts Options, transformCtx *resources.ResourceTransformationCtx) error {
71+
dependencyManager := opts.DependencyManager
72+
if transformCtx != nil {
73+
dependencyManager = transformCtx.DependencyManager // TODO1
7174
}
72-
73-
if opts.TargetPath != "" {
74-
ctx.OutPath = opts.TargetPath
75-
} else {
76-
ctx.ReplaceOutPathExtension(".js")
75+
if dependencyManager == nil {
76+
dependencyManager = identity.NopManager
7777
}
7878

79-
src, err := io.ReadAll(ctx.From)
80-
if err != nil {
79+
opts.ResolveDir = c.rs.Cfg.BaseConfig().WorkingDir // where node_modules gets resolved
80+
opts.TsConfig = c.rs.ResolveJSConfigFile("tsconfig.json")
81+
82+
if err := opts.validate(); err != nil {
8183
return err
8284
}
8385

84-
opts.sourceDir = filepath.FromSlash(path.Dir(ctx.SourcePath))
85-
opts.resolveDir = t.c.rs.Cfg.BaseConfig().WorkingDir // where node_modules gets resolved
86-
opts.contents = string(src)
87-
opts.mediaType = ctx.InMediaType
88-
opts.tsConfig = t.c.rs.ResolveJSConfigFile("tsconfig.json")
89-
9086
buildOptions, err := toBuildOptions(opts)
9187
if err != nil {
9288
return err
9389
}
9490

95-
buildOptions.Plugins, err = createBuildPlugins(ctx.DependencyManager, t.c, opts)
91+
buildOptions.Plugins, err = createBuildPlugins(c, dependencyManager, opts)
9692
if err != nil {
9793
return err
9894
}
@@ -113,7 +109,7 @@ func (t *buildTransformation) Transform(ctx *resources.ResourceTransformationCtx
113109
return fmt.Errorf("inject: absolute paths not supported, must be relative to /assets")
114110
}
115111

116-
m := resolveComponentInAssets(t.c.rs.Assets.Fs, impPath)
112+
m := resolveComponentInAssets(c.rs.Assets.Fs, impPath)
117113

118114
if m == nil {
119115
return fmt.Errorf("inject: file %q not found", ext)
@@ -138,7 +134,7 @@ func (t *buildTransformation) Transform(ctx *resources.ResourceTransformationCtx
138134
}
139135
path := loc.File
140136
if path == stdinImporter {
141-
path = ctx.SourcePath
137+
path = transformCtx.SourcePath
142138
}
143139

144140
errorMessage := msg.Text
@@ -154,7 +150,7 @@ func (t *buildTransformation) Transform(ctx *resources.ResourceTransformationCtx
154150
f, err = hugofs.Os.Open(path)
155151
} else {
156152
var fi os.FileInfo
157-
fi, err = t.c.sfs.Fs.Stat(path)
153+
fi, err = c.sfs.Fs.Stat(path)
158154
if err == nil {
159155
m := fi.(hugofs.FileMetaInfo).Meta()
160156
path = m.Filename
@@ -185,38 +181,37 @@ func (t *buildTransformation) Transform(ctx *resources.ResourceTransformationCtx
185181
// Return 1, log the rest.
186182
for i, err := range errors {
187183
if i > 0 {
188-
t.c.rs.Logger.Errorf("js.Build failed: %s", err)
184+
c.rs.Logger.Errorf("js.Build failed: %s", err)
189185
}
190186
}
191187

192188
return errors[0]
193189
}
194190

195-
if buildOptions.Sourcemap == api.SourceMapExternal {
196-
content := string(result.OutputFiles[1].Contents)
197-
symPath := path.Base(ctx.OutPath) + ".map"
198-
re := regexp.MustCompile(`//# sourceMappingURL=.*\n?`)
199-
content = re.ReplaceAllString(content, "//# sourceMappingURL="+symPath+"\n")
191+
if transformCtx != nil {
192+
if buildOptions.Sourcemap == api.SourceMapExternal {
193+
content := string(result.OutputFiles[1].Contents)
194+
symPath := path.Base(transformCtx.OutPath) + ".map"
195+
re := regexp.MustCompile(`//# sourceMappingURL=.*\n?`)
196+
content = re.ReplaceAllString(content, "//# sourceMappingURL="+symPath+"\n")
200197

201-
if err = ctx.PublishSourceMap(string(result.OutputFiles[0].Contents)); err != nil {
202-
return err
203-
}
204-
_, err := ctx.To.Write([]byte(content))
205-
if err != nil {
206-
return err
207-
}
208-
} else {
209-
_, err := ctx.To.Write(result.OutputFiles[0].Contents)
210-
if err != nil {
211-
return err
198+
if err = transformCtx.PublishSourceMap(string(result.OutputFiles[0].Contents)); err != nil {
199+
return err
200+
}
201+
_, err := transformCtx.To.Write([]byte(content))
202+
if err != nil {
203+
return err
204+
}
205+
} else {
206+
_, err := transformCtx.To.Write(result.OutputFiles[0].Contents)
207+
if err != nil {
208+
return err
209+
}
212210
}
211+
212+
return nil
213213
}
214-
return nil
215-
}
216214

217-
// Process process esbuild transform
218-
func (c *Client) Process(res resources.ResourceTransformer, opts map[string]any) (resource.Resource, error) {
219-
return res.Transform(
220-
&buildTransformation{c: c, optsm: opts},
221-
)
215+
// TODO1
216+
return nil
222217
}

0 commit comments

Comments
 (0)