diff options
Diffstat (limited to 'resources/resource_transformers')
-rw-r--r-- | resources/resource_transformers/js/build.go | 74 | ||||
-rw-r--r-- | resources/resource_transformers/js/options.go | 69 |
2 files changed, 102 insertions, 41 deletions
diff --git a/resources/resource_transformers/js/build.go b/resources/resource_transformers/js/build.go index 8a7c21592..3a7065e0d 100644 --- a/resources/resource_transformers/js/build.go +++ b/resources/resource_transformers/js/build.go @@ -18,14 +18,12 @@ import ( "fmt" "io/ioutil" "os" - "path" - "path/filepath" "strings" - "github.com/gohugoio/hugo/hugofs" - "github.com/spf13/afero" + "github.com/gohugoio/hugo/hugofs" + "github.com/gohugoio/hugo/common/herrors" "github.com/gohugoio/hugo/hugolib/filesystems" @@ -79,10 +77,9 @@ func (t *buildTransformation) Transform(ctx *resources.ResourceTransformationCtx return err } - sdir, _ := path.Split(ctx.SourcePath) opts.sourcefile = ctx.SourcePath - opts.resolveDir = t.c.sfs.RealFilename(sdir) opts.workDir = t.c.rs.WorkingDir + opts.resolveDir = opts.workDir opts.contents = string(src) opts.mediaType = ctx.InMediaType @@ -99,39 +96,54 @@ func (t *buildTransformation) Transform(ctx *resources.ResourceTransformationCtx result := api.Build(buildOptions) if len(result.Errors) > 0 { - first := result.Errors[0] - loc := first.Location - path := loc.File - - var err error - var f afero.File - var filename string - - if !strings.HasPrefix(path, "..") { - // Try first in the assets fs - var fi os.FileInfo - fi, err = t.c.rs.BaseFs.Assets.Fs.Stat(path) + + createErr := func(msg api.Message) error { + loc := msg.Location + path := loc.File + + var ( + f afero.File + err error + ) + + if strings.HasPrefix(path, nsImportHugo) { + path = strings.TrimPrefix(path, nsImportHugo+":") + f, err = hugofs.Os.Open(path) + } else { + var fi os.FileInfo + fi, err = t.c.sfs.Fs.Stat(path) + if err == nil { + m := fi.(hugofs.FileMetaInfo).Meta() + path = m.Filename() + f, err = m.Open() + } + + } + if err == nil { - m := fi.(hugofs.FileMetaInfo).Meta() - filename = m.Filename() - f, err = m.Open() + fe := herrors.NewFileError("js", 0, loc.Line, loc.Column, errors.New(msg.Text)) + err, _ := herrors.WithFileContext(fe, path, f, herrors.SimpleLineMatcher) + f.Close() + return err } + + return fmt.Errorf("%s", msg.Text) } - if f == nil { - path = filepath.Join(t.c.rs.WorkingDir, path) - filename = path - f, err = t.c.rs.Fs.Os.Open(path) + var errors []error + + for _, msg := range result.Errors { + errors = append(errors, createErr(msg)) } - if err == nil { - fe := herrors.NewFileError("js", 0, loc.Line, loc.Column, errors.New(first.Text)) - err, _ := herrors.WithFileContext(fe, filename, f, herrors.SimpleLineMatcher) - f.Close() - return err + // Return 1, log the rest. + for i, err := range errors { + if i > 0 { + t.c.rs.Logger.Errorf("js.Build failed: %s", err) + } } - return fmt.Errorf("%s", result.Errors[0].Text) + return errors[0] } ctx.To.Write(result.OutputFiles[0].Contents) diff --git a/resources/resource_transformers/js/options.go b/resources/resource_transformers/js/options.go index 84a6c1a78..654dbbab9 100644 --- a/resources/resource_transformers/js/options.go +++ b/resources/resource_transformers/js/options.go @@ -16,6 +16,7 @@ package js import ( "encoding/json" "fmt" + "io/ioutil" "path/filepath" "strings" "sync" @@ -31,6 +32,13 @@ import ( "github.com/spf13/cast" ) +const ( + nsImportHugo = "ns-hugo" + nsParams = "ns-params" + + stdinImporter = "<stdin>" +) + // Options esbuild configuration type Options struct { // If not set, the source path will be used as the base target path. @@ -111,6 +119,26 @@ type importCache struct { m map[string]api.OnResolveResult } +var extensionToLoaderMap = map[string]api.Loader{ + ".js": api.LoaderJS, + ".mjs": api.LoaderJS, + ".cjs": api.LoaderJS, + ".jsx": api.LoaderJSX, + ".ts": api.LoaderTS, + ".tsx": api.LoaderTSX, + ".css": api.LoaderCSS, + ".json": api.LoaderJSON, + ".txt": api.LoaderText, +} + +func loaderFromFilename(filename string) api.Loader { + l, found := extensionToLoaderMap[filepath.Ext(filename)] + if found { + return l + } + return api.LoaderJS +} + func createBuildPlugins(c *Client, opts Options) ([]api.Plugin, error) { fs := c.rs.Assets @@ -119,20 +147,21 @@ func createBuildPlugins(c *Client, opts Options) ([]api.Plugin, error) { } resolveImport := func(args api.OnResolveArgs) (api.OnResolveResult, error) { - relDir := fs.MakePathRelative(args.ResolveDir) - if relDir == "" { - // Not in a Hugo Module, probably in node_modules. - return api.OnResolveResult{}, nil + isStdin := args.Importer == stdinImporter + var relDir string + if !isStdin { + relDir = filepath.Dir(fs.MakePathRelative(args.Importer)) + } else { + relDir = filepath.Dir(opts.sourcefile) } impPath := args.Path - // stdin is the main entry file which already is at the relative root. // Imports not starting with a "." is assumed to live relative to /assets. // Hugo makes no assumptions about the directory structure below /assets. - if args.Importer != "<stdin>" && strings.HasPrefix(impPath, ".") { - impPath = filepath.Join(relDir, args.Path) + if relDir != "" && strings.HasPrefix(impPath, ".") { + impPath = filepath.Join(relDir, impPath) } findFirst := func(base string) hugofs.FileMeta { @@ -164,6 +193,7 @@ func createBuildPlugins(c *Client, opts Options) ([]api.Plugin, error) { // It may be a regular file imported without an extension. m = findFirst(impPath) } + // if m != nil { // Store the source root so we can create a jsconfig.json @@ -172,9 +202,11 @@ func createBuildPlugins(c *Client, opts Options) ([]api.Plugin, error) { // in server mode, we may get stale entries on renames etc., // but that shouldn't matter too much. c.rs.JSConfigBuilder.AddSourceRoot(m.SourceRoot()) - return api.OnResolveResult{Path: m.Filename(), Namespace: ""}, nil + return api.OnResolveResult{Path: m.Filename(), Namespace: nsImportHugo}, nil } + // Not found in /assets. Probably in node_modules. ESBuild will handle that + // rather complex logic. return api.OnResolveResult{}, nil } @@ -205,6 +237,23 @@ func createBuildPlugins(c *Client, opts Options) ([]api.Plugin, error) { return imp, nil }) + build.OnLoad(api.OnLoadOptions{Filter: `.*`, Namespace: nsImportHugo}, + func(args api.OnLoadArgs) (api.OnLoadResult, error) { + b, err := ioutil.ReadFile(args.Path) + + if err != nil { + return api.OnLoadResult{}, errors.Wrapf(err, "failed to read %q", args.Path) + } + c := string(b) + return api.OnLoadResult{ + // See https://github.com/evanw/esbuild/issues/502 + // This allows all modules to resolve dependencies + // in the main project's node_modules. + ResolveDir: opts.resolveDir, + Contents: &c, + Loader: loaderFromFilename(args.Path), + }, nil + }) }, } @@ -226,10 +275,10 @@ func createBuildPlugins(c *Client, opts Options) ([]api.Plugin, error) { func(args api.OnResolveArgs) (api.OnResolveResult, error) { return api.OnResolveResult{ Path: args.Path, - Namespace: "params", + Namespace: nsParams, }, nil }) - build.OnLoad(api.OnLoadOptions{Filter: `.*`, Namespace: "params"}, + build.OnLoad(api.OnLoadOptions{Filter: `.*`, Namespace: nsParams}, func(args api.OnLoadArgs) (api.OnLoadResult, error) { return api.OnLoadResult{ Contents: &bs, |