Skip to content

Commit

Permalink
Add js.Bundle
Browse files Browse the repository at this point in the history
Fixes #12626
  • Loading branch information
bep committed Sep 12, 2024
1 parent fe7e137 commit 61fba92
Show file tree
Hide file tree
Showing 11 changed files with 1,158 additions and 133 deletions.
14 changes: 14 additions & 0 deletions common/maps/scratch.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,20 @@ func (c *Scratch) Get(key string) any {
return val
}

// GetOrCreate returns the value for the given key if it exists, or creates it
// using the given func and stores that value in the map.
// For internal use.
func (c *Scratch) GetOrCreate(key string, create func() any) any {
c.mu.Lock()
defer c.mu.Unlock()
if val, found := c.values[key]; found {
return val
}
val := create()
c.values[key] = val
return val
}

// Values returns the raw backing map. Note that you should just use
// this method on the locally scoped Scratch instances you obtain via newScratch, not
// .Page.Scratch etc., as that will lead to concurrency issues.
Expand Down
117 changes: 56 additions & 61 deletions resources/resource_transformers/js/build.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2020 The Hugo Authors. All rights reserved.
// 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.
Expand All @@ -16,25 +16,20 @@ package js
import (
"errors"
"fmt"
"io"
"os"
"path"
"path/filepath"
"regexp"
"strings"

"github.com/spf13/afero"

"github.com/gohugoio/hugo/hugofs"
"github.com/gohugoio/hugo/media"

"github.com/evanw/esbuild/pkg/api"
"github.com/gohugoio/hugo/common/herrors"
"github.com/gohugoio/hugo/common/text"

"github.com/gohugoio/hugo/hugofs"
"github.com/gohugoio/hugo/hugolib/filesystems"
"github.com/gohugoio/hugo/resources/internal"
"github.com/gohugoio/hugo/identity"
"github.com/spf13/afero"

"github.com/evanw/esbuild/pkg/api"
"github.com/gohugoio/hugo/resources"
"github.com/gohugoio/hugo/resources/resource"
)
Expand All @@ -53,46 +48,47 @@ func New(fs *filesystems.SourceFilesystem, rs *resources.Spec) *Client {
}
}

type buildTransformation struct {
optsm map[string]any
c *Client
// ProcessExernal processes a resource with the user provided options.
func (c *Client) ProcessExernal(res resources.ResourceTransformer, opts map[string]any) (resource.Resource, error) {
return res.Transform(
&buildTransformation{c: c, optsm: opts},
)
}

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

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

opts, err := decodeOptions(t.optsm)
if err != nil {
return err
// Note that transformCtx may be nil.
func (c *Client) build(opts Options, transformCtx *resources.ResourceTransformationCtx) error {
dependencyManager := opts.DependencyManager
if transformCtx != nil {
dependencyManager = transformCtx.DependencyManager // TODO1
}

if opts.TargetPath != "" {
ctx.OutPath = opts.TargetPath
} else {
ctx.ReplaceOutPathExtension(".js")
if dependencyManager == nil {
dependencyManager = identity.NopManager
}

src, err := io.ReadAll(ctx.From)
if err != nil {
opts.ResolveDir = c.rs.Cfg.BaseConfig().WorkingDir // where node_modules gets resolved
opts.TsConfig = c.rs.ResolveJSConfigFile("tsconfig.json")

if err := opts.validate(); err != nil {
return err
}

opts.sourceDir = filepath.FromSlash(path.Dir(ctx.SourcePath))
opts.resolveDir = t.c.rs.Cfg.BaseConfig().WorkingDir // where node_modules gets resolved
opts.contents = string(src)
opts.mediaType = ctx.InMediaType
opts.tsConfig = t.c.rs.ResolveJSConfigFile("tsconfig.json")

buildOptions, err := toBuildOptions(opts)
if err != nil {
return err
}

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

m := resolveComponentInAssets(t.c.rs.Assets.Fs, impPath)
m := resolveComponentInAssets(c.rs.Assets.Fs, impPath)

if m == nil {
return fmt.Errorf("inject: file %q not found", ext)
Expand All @@ -138,7 +134,7 @@ func (t *buildTransformation) Transform(ctx *resources.ResourceTransformationCtx
}
path := loc.File
if path == stdinImporter {
path = ctx.SourcePath
path = transformCtx.SourcePath
}

errorMessage := msg.Text
Expand All @@ -154,7 +150,7 @@ func (t *buildTransformation) Transform(ctx *resources.ResourceTransformationCtx
f, err = hugofs.Os.Open(path)
} else {
var fi os.FileInfo
fi, err = t.c.sfs.Fs.Stat(path)
fi, err = c.sfs.Fs.Stat(path)
if err == nil {
m := fi.(hugofs.FileMetaInfo).Meta()
path = m.Filename
Expand Down Expand Up @@ -185,38 +181,37 @@ func (t *buildTransformation) Transform(ctx *resources.ResourceTransformationCtx
// Return 1, log the rest.
for i, err := range errors {
if i > 0 {
t.c.rs.Logger.Errorf("js.Build failed: %s", err)
c.rs.Logger.Errorf("js.Build failed: %s", err)
}
}

return errors[0]
}

if buildOptions.Sourcemap == api.SourceMapExternal {
content := string(result.OutputFiles[1].Contents)
symPath := path.Base(ctx.OutPath) + ".map"
re := regexp.MustCompile(`//# sourceMappingURL=.*\n?`)
content = re.ReplaceAllString(content, "//# sourceMappingURL="+symPath+"\n")
if transformCtx != nil {
if buildOptions.Sourcemap == api.SourceMapExternal {
content := string(result.OutputFiles[1].Contents)
symPath := path.Base(transformCtx.OutPath) + ".map"
re := regexp.MustCompile(`//# sourceMappingURL=.*\n?`)
content = re.ReplaceAllString(content, "//# sourceMappingURL="+symPath+"\n")

if err = ctx.PublishSourceMap(string(result.OutputFiles[0].Contents)); err != nil {
return err
}
_, err := ctx.To.Write([]byte(content))
if err != nil {
return err
}
} else {
_, err := ctx.To.Write(result.OutputFiles[0].Contents)
if err != nil {
return err
if err = transformCtx.PublishSourceMap(string(result.OutputFiles[0].Contents)); err != nil {
return err
}
_, err := transformCtx.To.Write([]byte(content))
if err != nil {
return err
}
} else {
_, err := transformCtx.To.Write(result.OutputFiles[0].Contents)
if err != nil {
return err
}
}

return nil
}
return nil
}

// Process process esbuild transform
func (c *Client) Process(res resources.ResourceTransformer, opts map[string]any) (resource.Resource, error) {
return res.Transform(
&buildTransformation{c: c, optsm: opts},
)
// TODO1
return nil
}
Loading

0 comments on commit 61fba92

Please sign in to comment.