@@ -20,6 +20,7 @@ import (
20
20
_ "embed"
21
21
"encoding/json"
22
22
"fmt"
23
+ "io"
23
24
"path"
24
25
"path/filepath"
25
26
"reflect"
@@ -34,19 +35,20 @@ import (
34
35
"github.com/gohugoio/hugo/common/maps"
35
36
"github.com/gohugoio/hugo/common/paths"
36
37
"github.com/gohugoio/hugo/deps"
38
+ "github.com/gohugoio/hugo/helpers"
37
39
"github.com/gohugoio/hugo/identity"
40
+ "github.com/gohugoio/hugo/internal/js"
38
41
"github.com/gohugoio/hugo/lazy"
39
42
"github.com/gohugoio/hugo/media"
40
43
"github.com/gohugoio/hugo/resources"
41
44
"github.com/gohugoio/hugo/resources/resource"
42
45
"github.com/gohugoio/hugo/resources/resource_factories/create"
43
46
"github.com/gohugoio/hugo/tpl"
44
47
"github.com/mitchellh/mapstructure"
45
- "github.com/spf13/afero"
46
48
"github.com/spf13/cast"
47
49
)
48
50
49
- var _ Batcher = (* batcher )(nil )
51
+ var _ js. Batcher = (* batcher )(nil )
50
52
51
53
const (
52
54
NsBatch = "_hugo-js-batch"
@@ -58,7 +60,7 @@ const (
58
60
//go:embed batch-esm-runner.gotmpl
59
61
var runnerTemplateStr string
60
62
61
- var _ BatchPackage = (* Package )(nil )
63
+ var _ js. BatchPackage = (* Package )(nil )
62
64
63
65
var _ buildToucher = (* optsHolder [scriptOptions ])(nil )
64
66
@@ -67,16 +69,17 @@ var (
67
69
_ isBuiltOrTouchedProvider = (* scriptGroup )(nil )
68
70
)
69
71
70
- func NewBatcherClient (deps * deps.Deps ) (* BatcherClient , error ) {
72
+ func NewBatcherClient (deps * deps.Deps ) (js. BatcherClient , error ) {
71
73
c := & BatcherClient {
72
74
d : deps ,
73
75
buildClient : NewBuildClient (deps .BaseFs .Assets , deps .ResourceSpec ),
74
76
createClient : create .New (deps .ResourceSpec ),
75
- bundlesCache : maps .NewCache [string , BatchPackage ](),
77
+ batcherStore : maps .NewCache [string , js.Batcher ](),
78
+ bundlesStore : maps .NewCache [string , js.BatchPackage ](),
76
79
}
77
80
78
81
deps .BuildEndListeners .Add (func (... any ) bool {
79
- c .bundlesCache .Reset ()
82
+ c .bundlesStore .Reset ()
80
83
return false
81
84
})
82
85
@@ -125,7 +128,7 @@ func (o *opts[K, C]) Reset() {
125
128
o .h .resetCounter ++
126
129
}
127
130
128
- func (o * opts [K , C ]) Get (id uint32 ) OptionsSetter {
131
+ func (o * opts [K , C ]) Get (id uint32 ) js. OptionsSetter {
129
132
var b * optsHolder [C ]
130
133
o .once .Do (func () {
131
134
b = o .h
@@ -184,18 +187,6 @@ func newOpts[K any, C optionsCompiler[C]](key K, optionsID string, defaults defa
184
187
}
185
188
}
186
189
187
- // BatchPackage holds a group of JavaScript resources.
188
- type BatchPackage interface {
189
- Groups () map [string ]resource.Resources
190
- }
191
-
192
- // Batcher is used to build JavaScript packages.
193
- type Batcher interface {
194
- Build (context.Context ) (BatchPackage , error )
195
- Config (ctx context.Context ) OptionsSetter
196
- Group (ctx context.Context , id string ) BatcherGroup
197
- }
198
-
199
190
// BatcherClient is a client for building JavaScript packages.
200
191
type BatcherClient struct {
201
192
d * deps.Deps
@@ -206,12 +197,13 @@ type BatcherClient struct {
206
197
createClient * create.Client
207
198
buildClient * BuildClient
208
199
209
- bundlesCache * maps.Cache [string , BatchPackage ]
200
+ batcherStore * maps.Cache [string , js.Batcher ]
201
+ bundlesStore * maps.Cache [string , js.BatchPackage ]
210
202
}
211
203
212
204
// New creates a new Batcher with the given ID.
213
205
// This will be typically created once and reused across rebuilds.
214
- func (c * BatcherClient ) New (id string ) (Batcher , error ) {
206
+ func (c * BatcherClient ) New (id string ) (js. Batcher , error ) {
215
207
var initErr error
216
208
c .once .Do (func () {
217
209
// We should fix the initialization order here (or use the Go template package directly), but we need to wait
@@ -288,6 +280,10 @@ func (c *BatcherClient) New(id string) (Batcher, error) {
288
280
return b , nil
289
281
}
290
282
283
+ func (c * BatcherClient ) Store () * maps.Cache [string , js.Batcher ] {
284
+ return c .batcherStore
285
+ }
286
+
291
287
func (c * BatcherClient ) buildBatchGroup (ctx context.Context , t * batchGroupTemplateContext ) (resource.Resource , string , error ) {
292
288
var buf bytes.Buffer
293
289
@@ -304,18 +300,6 @@ func (c *BatcherClient) buildBatchGroup(ctx context.Context, t *batchGroupTempla
304
300
return r , s , nil
305
301
}
306
302
307
- // BatcherGroup is a group of scripts and instances.
308
- type BatcherGroup interface {
309
- Instance (sid , iid string ) OptionsSetter
310
- Runner (id string ) OptionsSetter
311
- Script (id string ) OptionsSetter
312
- }
313
-
314
- // OptionsSetter is used to set options for a batch, script or instance.
315
- type OptionsSetter interface {
316
- SetOptions (map [string ]any ) string
317
- }
318
-
319
303
// Package holds a group of JavaScript resources.
320
304
type Package struct {
321
305
id string
@@ -353,9 +337,9 @@ type batcher struct {
353
337
}
354
338
355
339
// Build builds the batch if not already built or if it's stale.
356
- func (b * batcher ) Build (ctx context.Context ) (BatchPackage , error ) {
340
+ func (b * batcher ) Build (ctx context.Context ) (js. BatchPackage , error ) {
357
341
key := dynacache .CleanKey (b .id + ".js" )
358
- p , err := b .client .bundlesCache .GetOrCreate (key , func () (BatchPackage , error ) {
342
+ p , err := b .client .bundlesStore .GetOrCreate (key , func () (js. BatchPackage , error ) {
359
343
return b .build (ctx )
360
344
})
361
345
if err != nil {
@@ -364,11 +348,11 @@ func (b *batcher) Build(ctx context.Context) (BatchPackage, error) {
364
348
return p , nil
365
349
}
366
350
367
- func (b * batcher ) Config (ctx context.Context ) OptionsSetter {
351
+ func (b * batcher ) Config (ctx context.Context ) js. OptionsSetter {
368
352
return b .configOptions .Get (b .buildCount )
369
353
}
370
354
371
- func (b * batcher ) Group (ctx context.Context , id string ) BatcherGroup {
355
+ func (b * batcher ) Group (ctx context.Context , id string ) js. BatcherGroup {
372
356
if err := ValidateBatchID (id , false ); err != nil {
373
357
panic (err )
374
358
}
@@ -419,7 +403,7 @@ func (b *batcher) isStale() bool {
419
403
return false
420
404
}
421
405
422
- func (b * batcher ) build (ctx context.Context ) (BatchPackage , error ) {
406
+ func (b * batcher ) build (ctx context.Context ) (js. BatchPackage , error ) {
423
407
b .mu .Lock ()
424
408
defer b .mu .Unlock ()
425
409
defer func () {
@@ -463,6 +447,8 @@ func (b *batcher) doBuild(ctx context.Context) (*Package, error) {
463
447
pathGroup : maps .NewCache [string , string ](),
464
448
}
465
449
450
+ multihostBasePaths := b .client .d .ResourceSpec .MultihostTargetBasePaths
451
+
466
452
// Entry points passed to ESBuid.
467
453
var entryPoints []string
468
454
addResource := func (group , pth string , r resource.Resource , isResult bool ) {
@@ -701,15 +687,36 @@ func (b *batcher) doBuild(ctx context.Context) (*Package, error) {
701
687
702
688
if ! handled {
703
689
// Copy to destination.
704
- p := strings .TrimPrefix (o .Path , outDir )
705
- targetFilename := filepath .Join (b .id , p )
706
- fs := b .client .d .BaseFs .PublishFs
707
- if err := fs .MkdirAll (filepath .Dir (targetFilename ), 0o777 ); err != nil {
708
- return nil , fmt .Errorf ("failed to create dir %q: %w" , targetFilename , err )
690
+ // In a multihost setup, we will have multiple targets.
691
+ var targetFilenames []string
692
+ if len (multihostBasePaths ) > 0 {
693
+ for _ , base := range multihostBasePaths {
694
+ p := strings .TrimPrefix (o .Path , outDir )
695
+ targetFilename := filepath .Join (base , b .id , p )
696
+ targetFilenames = append (targetFilenames , targetFilename )
697
+ }
698
+ } else {
699
+ p := strings .TrimPrefix (o .Path , outDir )
700
+ targetFilename := filepath .Join (b .id , p )
701
+ targetFilenames = append (targetFilenames , targetFilename )
709
702
}
710
703
711
- if err := afero .WriteFile (fs , targetFilename , o .Contents , 0o666 ); err != nil {
712
- return nil , fmt .Errorf ("failed to write to %q: %w" , targetFilename , err )
704
+ fs := b .client .d .BaseFs .PublishFs
705
+
706
+ if err := func () error {
707
+ fw , err := helpers .OpenFilesForWriting (fs , targetFilenames ... )
708
+ if err != nil {
709
+ return err
710
+ }
711
+ defer fw .Close ()
712
+
713
+ fr := bytes .NewReader (o .Contents )
714
+
715
+ _ , err = io .Copy (fw , fr )
716
+
717
+ return err
718
+ }(); err != nil {
719
+ return nil , fmt .Errorf ("failed to copy to %q: %w" , targetFilenames , err )
713
720
}
714
721
}
715
722
}
@@ -845,7 +852,7 @@ type optionsGetSetter[K, C any] interface {
845
852
Key () K
846
853
Reset ()
847
854
848
- Get (uint32 ) OptionsSetter
855
+ Get (uint32 ) js. OptionsSetter
849
856
isStale () bool
850
857
currPrev () (map [string ]any , map [string ]any )
851
858
}
@@ -975,7 +982,7 @@ func (b *scriptGroup) IdentifierBase() string {
975
982
return b .id
976
983
}
977
984
978
- func (s * scriptGroup ) Instance (sid , id string ) OptionsSetter {
985
+ func (s * scriptGroup ) Instance (sid , id string ) js. OptionsSetter {
979
986
if err := ValidateBatchID (sid , false ); err != nil {
980
987
panic (err )
981
988
}
@@ -1014,7 +1021,7 @@ func (g *scriptGroup) Reset() {
1014
1021
}
1015
1022
}
1016
1023
1017
- func (s * scriptGroup ) Runner (id string ) OptionsSetter {
1024
+ func (s * scriptGroup ) Runner (id string ) js. OptionsSetter {
1018
1025
if err := ValidateBatchID (id , false ); err != nil {
1019
1026
panic (err )
1020
1027
}
@@ -1043,7 +1050,7 @@ func (s *scriptGroup) Runner(id string) OptionsSetter {
1043
1050
return s .runnersOptions [sid ].Get (s .b .buildCount )
1044
1051
}
1045
1052
1046
- func (s * scriptGroup ) Script (id string ) OptionsSetter {
1053
+ func (s * scriptGroup ) Script (id string ) js. OptionsSetter {
1047
1054
if err := ValidateBatchID (id , false ); err != nil {
1048
1055
panic (err )
1049
1056
}
0 commit comments