mirror of
https://github.com/gohugoio/hugo.git
synced 2025-08-17 21:01:26 +02:00
js: Fix js.Batch for multihost setups
Note that this is an unreleased feature. Fixes #13151
This commit is contained in:
7
deps/deps.go
vendored
7
deps/deps.go
vendored
@@ -24,6 +24,7 @@ import (
|
|||||||
"github.com/gohugoio/hugo/helpers"
|
"github.com/gohugoio/hugo/helpers"
|
||||||
"github.com/gohugoio/hugo/hugofs"
|
"github.com/gohugoio/hugo/hugofs"
|
||||||
"github.com/gohugoio/hugo/identity"
|
"github.com/gohugoio/hugo/identity"
|
||||||
|
"github.com/gohugoio/hugo/internal/js"
|
||||||
"github.com/gohugoio/hugo/internal/warpc"
|
"github.com/gohugoio/hugo/internal/warpc"
|
||||||
"github.com/gohugoio/hugo/media"
|
"github.com/gohugoio/hugo/media"
|
||||||
"github.com/gohugoio/hugo/resources/page"
|
"github.com/gohugoio/hugo/resources/page"
|
||||||
@@ -105,6 +106,12 @@ type Deps struct {
|
|||||||
// TODO(bep) rethink this re. a plugin setup, but this will have to do for now.
|
// TODO(bep) rethink this re. a plugin setup, but this will have to do for now.
|
||||||
WasmDispatchers *warpc.Dispatchers
|
WasmDispatchers *warpc.Dispatchers
|
||||||
|
|
||||||
|
// The JS batcher client.
|
||||||
|
JSBatcherClient js.BatcherClient
|
||||||
|
|
||||||
|
// The JS batcher client.
|
||||||
|
// JSBatcherClient *esbuild.BatcherClient
|
||||||
|
|
||||||
isClosed bool
|
isClosed bool
|
||||||
|
|
||||||
*globalErrHandler
|
*globalErrHandler
|
||||||
|
@@ -67,7 +67,7 @@ func New(fs *hugofs.Fs, cfg config.AllProvider) (*Paths, error) {
|
|||||||
var multihostTargetBasePaths []string
|
var multihostTargetBasePaths []string
|
||||||
if cfg.IsMultihost() && len(cfg.Languages()) > 1 {
|
if cfg.IsMultihost() && len(cfg.Languages()) > 1 {
|
||||||
for _, l := range cfg.Languages() {
|
for _, l := range cfg.Languages() {
|
||||||
multihostTargetBasePaths = append(multihostTargetBasePaths, l.Lang)
|
multihostTargetBasePaths = append(multihostTargetBasePaths, hpaths.ToSlashPreserveLeading(l.Lang))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -42,6 +42,7 @@ import (
|
|||||||
"github.com/gohugoio/hugo/deps"
|
"github.com/gohugoio/hugo/deps"
|
||||||
"github.com/gohugoio/hugo/hugolib/doctree"
|
"github.com/gohugoio/hugo/hugolib/doctree"
|
||||||
"github.com/gohugoio/hugo/hugolib/pagesfromdata"
|
"github.com/gohugoio/hugo/hugolib/pagesfromdata"
|
||||||
|
"github.com/gohugoio/hugo/internal/js/esbuild"
|
||||||
"github.com/gohugoio/hugo/internal/warpc"
|
"github.com/gohugoio/hugo/internal/warpc"
|
||||||
"github.com/gohugoio/hugo/langs/i18n"
|
"github.com/gohugoio/hugo/langs/i18n"
|
||||||
"github.com/gohugoio/hugo/modules"
|
"github.com/gohugoio/hugo/modules"
|
||||||
@@ -205,6 +206,12 @@ func NewHugoSites(cfg deps.DepsCfg) (*HugoSites, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
batcherClient, err := esbuild.NewBatcherClient(firstSiteDeps)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
firstSiteDeps.JSBatcherClient = batcherClient
|
||||||
|
|
||||||
confm := cfg.Configs
|
confm := cfg.Configs
|
||||||
if err := confm.Validate(logger); err != nil {
|
if err := confm.Validate(logger); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -313,7 +320,6 @@ func NewHugoSites(cfg deps.DepsCfg) (*HugoSites, error) {
|
|||||||
return li.Lang < lj.Lang
|
return li.Lang < lj.Lang
|
||||||
})
|
})
|
||||||
|
|
||||||
var err error
|
|
||||||
h, err = newHugoSites(cfg, firstSiteDeps, pageTrees, sites)
|
h, err = newHugoSites(cfg, firstSiteDeps, pageTrees, sites)
|
||||||
if err == nil && h == nil {
|
if err == nil && h == nil {
|
||||||
panic("hugo: newHugoSitesNew returned nil error and nil HugoSites")
|
panic("hugo: newHugoSitesNew returned nil error and nil HugoSites")
|
||||||
|
51
internal/js/api.go
Normal file
51
internal/js/api.go
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
// Copyright 2024 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 js
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/common/maps"
|
||||||
|
"github.com/gohugoio/hugo/resources/resource"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BatcherClient is used to do JS batch operations.
|
||||||
|
type BatcherClient interface {
|
||||||
|
New(id string) (Batcher, error)
|
||||||
|
Store() *maps.Cache[string, Batcher]
|
||||||
|
}
|
||||||
|
|
||||||
|
// BatchPackage holds a group of JavaScript resources.
|
||||||
|
type BatchPackage interface {
|
||||||
|
Groups() map[string]resource.Resources
|
||||||
|
}
|
||||||
|
|
||||||
|
// Batcher is used to build JavaScript packages.
|
||||||
|
type Batcher interface {
|
||||||
|
Build(context.Context) (BatchPackage, error)
|
||||||
|
Config(ctx context.Context) OptionsSetter
|
||||||
|
Group(ctx context.Context, id string) BatcherGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
// BatcherGroup is a group of scripts and instances.
|
||||||
|
type BatcherGroup interface {
|
||||||
|
Instance(sid, iid string) OptionsSetter
|
||||||
|
Runner(id string) OptionsSetter
|
||||||
|
Script(id string) OptionsSetter
|
||||||
|
}
|
||||||
|
|
||||||
|
// OptionsSetter is used to set options for a batch, script or instance.
|
||||||
|
type OptionsSetter interface {
|
||||||
|
SetOptions(map[string]any) string
|
||||||
|
}
|
@@ -20,6 +20,7 @@ import (
|
|||||||
_ "embed"
|
_ "embed"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
@@ -34,7 +35,9 @@ import (
|
|||||||
"github.com/gohugoio/hugo/common/maps"
|
"github.com/gohugoio/hugo/common/maps"
|
||||||
"github.com/gohugoio/hugo/common/paths"
|
"github.com/gohugoio/hugo/common/paths"
|
||||||
"github.com/gohugoio/hugo/deps"
|
"github.com/gohugoio/hugo/deps"
|
||||||
|
"github.com/gohugoio/hugo/helpers"
|
||||||
"github.com/gohugoio/hugo/identity"
|
"github.com/gohugoio/hugo/identity"
|
||||||
|
"github.com/gohugoio/hugo/internal/js"
|
||||||
"github.com/gohugoio/hugo/lazy"
|
"github.com/gohugoio/hugo/lazy"
|
||||||
"github.com/gohugoio/hugo/media"
|
"github.com/gohugoio/hugo/media"
|
||||||
"github.com/gohugoio/hugo/resources"
|
"github.com/gohugoio/hugo/resources"
|
||||||
@@ -42,11 +45,10 @@ import (
|
|||||||
"github.com/gohugoio/hugo/resources/resource_factories/create"
|
"github.com/gohugoio/hugo/resources/resource_factories/create"
|
||||||
"github.com/gohugoio/hugo/tpl"
|
"github.com/gohugoio/hugo/tpl"
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
"github.com/spf13/afero"
|
|
||||||
"github.com/spf13/cast"
|
"github.com/spf13/cast"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ Batcher = (*batcher)(nil)
|
var _ js.Batcher = (*batcher)(nil)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
NsBatch = "_hugo-js-batch"
|
NsBatch = "_hugo-js-batch"
|
||||||
@@ -58,7 +60,7 @@ const (
|
|||||||
//go:embed batch-esm-runner.gotmpl
|
//go:embed batch-esm-runner.gotmpl
|
||||||
var runnerTemplateStr string
|
var runnerTemplateStr string
|
||||||
|
|
||||||
var _ BatchPackage = (*Package)(nil)
|
var _ js.BatchPackage = (*Package)(nil)
|
||||||
|
|
||||||
var _ buildToucher = (*optsHolder[scriptOptions])(nil)
|
var _ buildToucher = (*optsHolder[scriptOptions])(nil)
|
||||||
|
|
||||||
@@ -67,16 +69,17 @@ var (
|
|||||||
_ isBuiltOrTouchedProvider = (*scriptGroup)(nil)
|
_ isBuiltOrTouchedProvider = (*scriptGroup)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewBatcherClient(deps *deps.Deps) (*BatcherClient, error) {
|
func NewBatcherClient(deps *deps.Deps) (js.BatcherClient, error) {
|
||||||
c := &BatcherClient{
|
c := &BatcherClient{
|
||||||
d: deps,
|
d: deps,
|
||||||
buildClient: NewBuildClient(deps.BaseFs.Assets, deps.ResourceSpec),
|
buildClient: NewBuildClient(deps.BaseFs.Assets, deps.ResourceSpec),
|
||||||
createClient: create.New(deps.ResourceSpec),
|
createClient: create.New(deps.ResourceSpec),
|
||||||
bundlesCache: maps.NewCache[string, BatchPackage](),
|
batcherStore: maps.NewCache[string, js.Batcher](),
|
||||||
|
bundlesStore: maps.NewCache[string, js.BatchPackage](),
|
||||||
}
|
}
|
||||||
|
|
||||||
deps.BuildEndListeners.Add(func(...any) bool {
|
deps.BuildEndListeners.Add(func(...any) bool {
|
||||||
c.bundlesCache.Reset()
|
c.bundlesStore.Reset()
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -125,7 +128,7 @@ func (o *opts[K, C]) Reset() {
|
|||||||
o.h.resetCounter++
|
o.h.resetCounter++
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *opts[K, C]) Get(id uint32) OptionsSetter {
|
func (o *opts[K, C]) Get(id uint32) js.OptionsSetter {
|
||||||
var b *optsHolder[C]
|
var b *optsHolder[C]
|
||||||
o.once.Do(func() {
|
o.once.Do(func() {
|
||||||
b = o.h
|
b = o.h
|
||||||
@@ -184,18 +187,6 @@ func newOpts[K any, C optionsCompiler[C]](key K, optionsID string, defaults defa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// BatchPackage holds a group of JavaScript resources.
|
|
||||||
type BatchPackage interface {
|
|
||||||
Groups() map[string]resource.Resources
|
|
||||||
}
|
|
||||||
|
|
||||||
// Batcher is used to build JavaScript packages.
|
|
||||||
type Batcher interface {
|
|
||||||
Build(context.Context) (BatchPackage, error)
|
|
||||||
Config(ctx context.Context) OptionsSetter
|
|
||||||
Group(ctx context.Context, id string) BatcherGroup
|
|
||||||
}
|
|
||||||
|
|
||||||
// BatcherClient is a client for building JavaScript packages.
|
// BatcherClient is a client for building JavaScript packages.
|
||||||
type BatcherClient struct {
|
type BatcherClient struct {
|
||||||
d *deps.Deps
|
d *deps.Deps
|
||||||
@@ -206,12 +197,13 @@ type BatcherClient struct {
|
|||||||
createClient *create.Client
|
createClient *create.Client
|
||||||
buildClient *BuildClient
|
buildClient *BuildClient
|
||||||
|
|
||||||
bundlesCache *maps.Cache[string, BatchPackage]
|
batcherStore *maps.Cache[string, js.Batcher]
|
||||||
|
bundlesStore *maps.Cache[string, js.BatchPackage]
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new Batcher with the given ID.
|
// New creates a new Batcher with the given ID.
|
||||||
// This will be typically created once and reused across rebuilds.
|
// This will be typically created once and reused across rebuilds.
|
||||||
func (c *BatcherClient) New(id string) (Batcher, error) {
|
func (c *BatcherClient) New(id string) (js.Batcher, error) {
|
||||||
var initErr error
|
var initErr error
|
||||||
c.once.Do(func() {
|
c.once.Do(func() {
|
||||||
// We should fix the initialization order here (or use the Go template package directly), but we need to wait
|
// 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) {
|
|||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *BatcherClient) Store() *maps.Cache[string, js.Batcher] {
|
||||||
|
return c.batcherStore
|
||||||
|
}
|
||||||
|
|
||||||
func (c *BatcherClient) buildBatchGroup(ctx context.Context, t *batchGroupTemplateContext) (resource.Resource, string, error) {
|
func (c *BatcherClient) buildBatchGroup(ctx context.Context, t *batchGroupTemplateContext) (resource.Resource, string, error) {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
|
||||||
@@ -304,18 +300,6 @@ func (c *BatcherClient) buildBatchGroup(ctx context.Context, t *batchGroupTempla
|
|||||||
return r, s, nil
|
return r, s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// BatcherGroup is a group of scripts and instances.
|
|
||||||
type BatcherGroup interface {
|
|
||||||
Instance(sid, iid string) OptionsSetter
|
|
||||||
Runner(id string) OptionsSetter
|
|
||||||
Script(id string) OptionsSetter
|
|
||||||
}
|
|
||||||
|
|
||||||
// OptionsSetter is used to set options for a batch, script or instance.
|
|
||||||
type OptionsSetter interface {
|
|
||||||
SetOptions(map[string]any) string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Package holds a group of JavaScript resources.
|
// Package holds a group of JavaScript resources.
|
||||||
type Package struct {
|
type Package struct {
|
||||||
id string
|
id string
|
||||||
@@ -353,9 +337,9 @@ type batcher struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Build builds the batch if not already built or if it's stale.
|
// Build builds the batch if not already built or if it's stale.
|
||||||
func (b *batcher) Build(ctx context.Context) (BatchPackage, error) {
|
func (b *batcher) Build(ctx context.Context) (js.BatchPackage, error) {
|
||||||
key := dynacache.CleanKey(b.id + ".js")
|
key := dynacache.CleanKey(b.id + ".js")
|
||||||
p, err := b.client.bundlesCache.GetOrCreate(key, func() (BatchPackage, error) {
|
p, err := b.client.bundlesStore.GetOrCreate(key, func() (js.BatchPackage, error) {
|
||||||
return b.build(ctx)
|
return b.build(ctx)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -364,11 +348,11 @@ func (b *batcher) Build(ctx context.Context) (BatchPackage, error) {
|
|||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *batcher) Config(ctx context.Context) OptionsSetter {
|
func (b *batcher) Config(ctx context.Context) js.OptionsSetter {
|
||||||
return b.configOptions.Get(b.buildCount)
|
return b.configOptions.Get(b.buildCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *batcher) Group(ctx context.Context, id string) BatcherGroup {
|
func (b *batcher) Group(ctx context.Context, id string) js.BatcherGroup {
|
||||||
if err := ValidateBatchID(id, false); err != nil {
|
if err := ValidateBatchID(id, false); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -419,7 +403,7 @@ func (b *batcher) isStale() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *batcher) build(ctx context.Context) (BatchPackage, error) {
|
func (b *batcher) build(ctx context.Context) (js.BatchPackage, error) {
|
||||||
b.mu.Lock()
|
b.mu.Lock()
|
||||||
defer b.mu.Unlock()
|
defer b.mu.Unlock()
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -463,6 +447,8 @@ func (b *batcher) doBuild(ctx context.Context) (*Package, error) {
|
|||||||
pathGroup: maps.NewCache[string, string](),
|
pathGroup: maps.NewCache[string, string](),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
multihostBasePaths := b.client.d.ResourceSpec.MultihostTargetBasePaths
|
||||||
|
|
||||||
// Entry points passed to ESBuid.
|
// Entry points passed to ESBuid.
|
||||||
var entryPoints []string
|
var entryPoints []string
|
||||||
addResource := func(group, pth string, r resource.Resource, isResult bool) {
|
addResource := func(group, pth string, r resource.Resource, isResult bool) {
|
||||||
@@ -701,15 +687,36 @@ func (b *batcher) doBuild(ctx context.Context) (*Package, error) {
|
|||||||
|
|
||||||
if !handled {
|
if !handled {
|
||||||
// Copy to destination.
|
// Copy to destination.
|
||||||
|
// In a multihost setup, we will have multiple targets.
|
||||||
|
var targetFilenames []string
|
||||||
|
if len(multihostBasePaths) > 0 {
|
||||||
|
for _, base := range multihostBasePaths {
|
||||||
|
p := strings.TrimPrefix(o.Path, outDir)
|
||||||
|
targetFilename := filepath.Join(base, b.id, p)
|
||||||
|
targetFilenames = append(targetFilenames, targetFilename)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
p := strings.TrimPrefix(o.Path, outDir)
|
p := strings.TrimPrefix(o.Path, outDir)
|
||||||
targetFilename := filepath.Join(b.id, p)
|
targetFilename := filepath.Join(b.id, p)
|
||||||
fs := b.client.d.BaseFs.PublishFs
|
targetFilenames = append(targetFilenames, targetFilename)
|
||||||
if err := fs.MkdirAll(filepath.Dir(targetFilename), 0o777); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create dir %q: %w", targetFilename, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := afero.WriteFile(fs, targetFilename, o.Contents, 0o666); err != nil {
|
fs := b.client.d.BaseFs.PublishFs
|
||||||
return nil, fmt.Errorf("failed to write to %q: %w", targetFilename, err)
|
|
||||||
|
if err := func() error {
|
||||||
|
fw, err := helpers.OpenFilesForWriting(fs, targetFilenames...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer fw.Close()
|
||||||
|
|
||||||
|
fr := bytes.NewReader(o.Contents)
|
||||||
|
|
||||||
|
_, err = io.Copy(fw, fr)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}(); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to copy to %q: %w", targetFilenames, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -845,7 +852,7 @@ type optionsGetSetter[K, C any] interface {
|
|||||||
Key() K
|
Key() K
|
||||||
Reset()
|
Reset()
|
||||||
|
|
||||||
Get(uint32) OptionsSetter
|
Get(uint32) js.OptionsSetter
|
||||||
isStale() bool
|
isStale() bool
|
||||||
currPrev() (map[string]any, map[string]any)
|
currPrev() (map[string]any, map[string]any)
|
||||||
}
|
}
|
||||||
@@ -975,7 +982,7 @@ func (b *scriptGroup) IdentifierBase() string {
|
|||||||
return b.id
|
return b.id
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *scriptGroup) Instance(sid, id string) OptionsSetter {
|
func (s *scriptGroup) Instance(sid, id string) js.OptionsSetter {
|
||||||
if err := ValidateBatchID(sid, false); err != nil {
|
if err := ValidateBatchID(sid, false); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -1014,7 +1021,7 @@ func (g *scriptGroup) Reset() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *scriptGroup) Runner(id string) OptionsSetter {
|
func (s *scriptGroup) Runner(id string) js.OptionsSetter {
|
||||||
if err := ValidateBatchID(id, false); err != nil {
|
if err := ValidateBatchID(id, false); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -1043,7 +1050,7 @@ func (s *scriptGroup) Runner(id string) OptionsSetter {
|
|||||||
return s.runnersOptions[sid].Get(s.b.buildCount)
|
return s.runnersOptions[sid].Get(s.b.buildCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *scriptGroup) Script(id string) OptionsSetter {
|
func (s *scriptGroup) Script(id string) js.OptionsSetter {
|
||||||
if err := ValidateBatchID(id, false); err != nil {
|
if err := ValidateBatchID(id, false); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@@ -184,6 +184,69 @@ func TestBatchEditScriptParam(t *testing.T) {
|
|||||||
b.AssertFileContent("public/mybatch/mygroup.js", "param-p1-main-edited")
|
b.AssertFileContent("public/mybatch/mygroup.js", "param-p1-main-edited")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBatchMultiHost(t *testing.T) {
|
||||||
|
files := `
|
||||||
|
-- hugo.toml --
|
||||||
|
disableKinds = ["taxonomy", "term", "section"]
|
||||||
|
[languages]
|
||||||
|
[languages.en]
|
||||||
|
weight = 1
|
||||||
|
baseURL = "https://example.com/en"
|
||||||
|
[languages.fr]
|
||||||
|
weight = 2
|
||||||
|
baseURL = "https://example.com/fr"
|
||||||
|
disableLiveReload = true
|
||||||
|
-- assets/js/styles.css --
|
||||||
|
body {
|
||||||
|
background-color: red;
|
||||||
|
}
|
||||||
|
-- assets/js/main.js --
|
||||||
|
import * as foo from 'mylib';
|
||||||
|
console.log("Hello, Main!");
|
||||||
|
-- assets/js/runner.js --
|
||||||
|
console.log("Hello, Runner!");
|
||||||
|
-- node_modules/mylib/index.js --
|
||||||
|
console.log("Hello, My Lib!");
|
||||||
|
-- layouts/index.html --
|
||||||
|
Home.
|
||||||
|
{{ $batch := (js.Batch "mybatch") }}
|
||||||
|
{{ with $batch.Config }}
|
||||||
|
{{ .SetOptions (dict
|
||||||
|
"params" (dict "id" "config")
|
||||||
|
"sourceMap" ""
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
{{ end }}
|
||||||
|
{{ with (templates.Defer (dict "key" "global")) }}
|
||||||
|
Defer:
|
||||||
|
{{ $batch := (js.Batch "mybatch") }}
|
||||||
|
{{ range $k, $v := $batch.Build.Groups }}
|
||||||
|
{{ range $kk, $vv := . -}}
|
||||||
|
{{ $k }}: {{ .RelPermalink }}
|
||||||
|
{{ end }}
|
||||||
|
{{ end -}}
|
||||||
|
{{ end }}
|
||||||
|
{{ $batch := (js.Batch "mybatch") }}
|
||||||
|
{{ with $batch.Group "mygroup" }}
|
||||||
|
{{ with .Runner "run" }}
|
||||||
|
{{ .SetOptions (dict "resource" (resources.Get "js/runner.js")) }}
|
||||||
|
{{ end }}
|
||||||
|
{{ with .Script "main" }}
|
||||||
|
{{ .SetOptions (dict "resource" (resources.Get "js/main.js") "params" (dict "p1" "param-p1-main" )) }}
|
||||||
|
{{ end }}
|
||||||
|
{{ with .Instance "main" "i1" }}
|
||||||
|
{{ .SetOptions (dict "params" (dict "title" "Instance 1")) }}
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
|
||||||
|
`
|
||||||
|
b := hugolib.Test(t, files, hugolib.TestOptWithOSFs())
|
||||||
|
b.AssertPublishDir(
|
||||||
|
"en/mybatch/chunk-TOZKWCDE.js", "en/mybatch/mygroup.js ",
|
||||||
|
"fr/mybatch/mygroup.js", "fr/mybatch/chunk-TOZKWCDE.js")
|
||||||
|
}
|
||||||
|
|
||||||
func TestBatchRenameBundledScript(t *testing.T) {
|
func TestBatchRenameBundledScript(t *testing.T) {
|
||||||
files := jsBatchFilesTemplate
|
files := jsBatchFilesTemplate
|
||||||
b := hugolib.TestRunning(t, files, hugolib.TestOptWithOSFs())
|
b := hugolib.TestRunning(t, files, hugolib.TestOptWithOSFs())
|
||||||
|
@@ -141,13 +141,6 @@ func (fd *ResourceSourceDescriptor) init(r *Spec) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fd.TargetPath = paths.ToSlashPreserveLeading(fd.TargetPath)
|
fd.TargetPath = paths.ToSlashPreserveLeading(fd.TargetPath)
|
||||||
for i, base := range fd.TargetBasePaths {
|
|
||||||
dir := paths.ToSlashPreserveLeading(base)
|
|
||||||
if dir == "/" {
|
|
||||||
dir = ""
|
|
||||||
}
|
|
||||||
fd.TargetBasePaths[i] = dir
|
|
||||||
}
|
|
||||||
|
|
||||||
if fd.NameNormalized == "" {
|
if fd.NameNormalized == "" {
|
||||||
fd.NameNormalized = fd.TargetPath
|
fd.NameNormalized = fd.TargetPath
|
||||||
|
18
tpl/js/js.go
18
tpl/js/js.go
@@ -17,8 +17,8 @@ package js
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/common/maps"
|
|
||||||
"github.com/gohugoio/hugo/deps"
|
"github.com/gohugoio/hugo/deps"
|
||||||
|
"github.com/gohugoio/hugo/internal/js"
|
||||||
"github.com/gohugoio/hugo/internal/js/esbuild"
|
"github.com/gohugoio/hugo/internal/js/esbuild"
|
||||||
"github.com/gohugoio/hugo/resources"
|
"github.com/gohugoio/hugo/resources"
|
||||||
"github.com/gohugoio/hugo/resources/resource"
|
"github.com/gohugoio/hugo/resources/resource"
|
||||||
@@ -34,16 +34,9 @@ func New(d *deps.Deps) (*Namespace, error) {
|
|||||||
return &Namespace{}, nil
|
return &Namespace{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
batcherClient, err := esbuild.NewBatcherClient(d)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Namespace{
|
return &Namespace{
|
||||||
d: d,
|
d: d,
|
||||||
jsTransformClient: jstransform.New(d.BaseFs.Assets, d.ResourceSpec),
|
jsTransformClient: jstransform.New(d.BaseFs.Assets, d.ResourceSpec),
|
||||||
jsBatcherClient: batcherClient,
|
|
||||||
jsBatcherStore: maps.NewCache[string, esbuild.Batcher](),
|
|
||||||
createClient: create.New(d.ResourceSpec),
|
createClient: create.New(d.ResourceSpec),
|
||||||
babelClient: babel.New(d.ResourceSpec),
|
babelClient: babel.New(d.ResourceSpec),
|
||||||
}, nil
|
}, nil
|
||||||
@@ -56,8 +49,6 @@ type Namespace struct {
|
|||||||
jsTransformClient *jstransform.Client
|
jsTransformClient *jstransform.Client
|
||||||
createClient *create.Client
|
createClient *create.Client
|
||||||
babelClient *babel.Client
|
babelClient *babel.Client
|
||||||
jsBatcherClient *esbuild.BatcherClient
|
|
||||||
jsBatcherStore *maps.Cache[string, esbuild.Batcher]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build processes the given Resource with ESBuild.
|
// Build processes the given Resource with ESBuild.
|
||||||
@@ -90,12 +81,13 @@ func (ns *Namespace) Build(args ...any) (resource.Resource, error) {
|
|||||||
// Repeated calls with the same ID will return the same Batcher.
|
// Repeated calls with the same ID will return the same Batcher.
|
||||||
// The ID will be used to name the root directory of the batch.
|
// The ID will be used to name the root directory of the batch.
|
||||||
// Forward slashes in the ID is allowed.
|
// Forward slashes in the ID is allowed.
|
||||||
func (ns *Namespace) Batch(id string) (esbuild.Batcher, error) {
|
func (ns *Namespace) Batch(id string) (js.Batcher, error) {
|
||||||
if err := esbuild.ValidateBatchID(id, true); err != nil {
|
if err := esbuild.ValidateBatchID(id, true); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
b, err := ns.jsBatcherStore.GetOrCreate(id, func() (esbuild.Batcher, error) {
|
|
||||||
return ns.jsBatcherClient.New(id)
|
b, err := ns.d.JSBatcherClient.Store().GetOrCreate(id, func() (js.Batcher, error) {
|
||||||
|
return ns.d.JSBatcherClient.New(id)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
Reference in New Issue
Block a user