From 640727de96448c4b8d9e9223c683d99cccd40292 Mon Sep 17 00:00:00 2001 From: Luke Sheard Date: Sat, 4 Dec 2021 01:59:15 +0000 Subject: [PATCH] Add ability to pass '[ext]' template to output file name templates (#1799) --- internal/bundler/bundler.go | 7 +-- internal/bundler/bundler_default_test.go | 32 +++++++++++++ internal/bundler/bundler_loader_test.go | 30 ++++++++++++ internal/bundler/linker.go | 10 ++-- .../bundler/snapshots/snapshots_loader.txt | 46 +++++++++++++++++++ internal/config/config.go | 9 ++++ pkg/api/api_impl.go | 4 ++ 7 files changed, 130 insertions(+), 8 deletions(-) diff --git a/internal/bundler/bundler.go b/internal/bundler/bundler.go index 519af0b1774..13d01f9d508 100644 --- a/internal/bundler/bundler.go +++ b/internal/bundler/bundler.go @@ -1812,21 +1812,22 @@ func (s *scanner) processScannedFiles() []scannerFile { // Generate the input for the template _, _, originalExt := logger.PlatformIndependentPathDirBaseExt(result.file.inputFile.Source.KeyPath.Text) - dir, base, ext := pathRelativeToOutbase( + dir, base := pathRelativeToOutbase( &result.file.inputFile, &s.options, s.fs, - originalExt, /* avoidIndex */ false, /* customFilePath */ "", ) // Apply the asset path template + templateExt := strings.TrimPrefix(originalExt, ".") relPath := config.TemplateToString(config.SubstituteTemplate(s.options.AssetPathTemplate, config.PathPlaceholders{ Dir: &dir, Name: &base, Hash: &hash, - })) + ext + Ext: &templateExt, + })) + originalExt // Optionally add metadata about the file var jsonMetadataChunk string diff --git a/internal/bundler/bundler_default_test.go b/internal/bundler/bundler_default_test.go index 7b3c1278d1b..b8a3a86198d 100644 --- a/internal/bundler/bundler_default_test.go +++ b/internal/bundler/bundler_default_test.go @@ -4981,3 +4981,35 @@ func TestEntryNamesNonPortableCharacter(t *testing.T) { }, }) } + +func TestEntryNamesChunkNamesExtPlaceholder(t *testing.T) { + loader_suite.expectBundled(t, bundled{ + files: map[string]string{ + "/src/entries/entry1.js": `import "../lib/shared.js"; import "./entry1.css"; console.log('entry1')`, + "/src/entries/entry2.js": `import "../lib/shared.js"; import "./entry2.css"; console.log('entry2')`, + "/src/entries/entry1.css": `a:after { content: "entry1" }`, + "/src/entries/entry2.css": `a:after { content: "entry2" }`, + "/src/lib/shared.js": `console.log('shared')`, + }, + entryPaths: []string{ + "/src/entries/entry1.js", + "/src/entries/entry2.js", + }, + options: config.Options{ + Mode: config.ModeBundle, + AbsOutputBase: "/src", + AbsOutputDir: "/out", + CodeSplitting: true, + EntryPathTemplate: []config.PathTemplate{ + {Data: "main/", Placeholder: config.ExtPlaceholder}, + {Data: "/", Placeholder: config.NamePlaceholder}, + {Data: "-", Placeholder: config.HashPlaceholder}, + }, + ChunkPathTemplate: []config.PathTemplate{ + {Data: "common/", Placeholder: config.ExtPlaceholder}, + {Data: "/", Placeholder: config.NamePlaceholder}, + {Data: "-", Placeholder: config.HashPlaceholder}, + }, + }, + }) +} diff --git a/internal/bundler/bundler_loader_test.go b/internal/bundler/bundler_loader_test.go index 0a02d0e1fc2..ef59c4afbd4 100644 --- a/internal/bundler/bundler_loader_test.go +++ b/internal/bundler/bundler_loader_test.go @@ -469,6 +469,36 @@ func TestLoaderFileRelativePathAssetNamesJS(t *testing.T) { }) } +func TestLoaderFileExtPathAssetNamesJS(t *testing.T) { + loader_suite.expectBundled(t, bundled{ + files: map[string]string{ + "/src/entries/entry.js": ` + import x from '../images/image.png' + import y from '../uploads/file.txt' + console.log(x, y) + `, + "/src/images/image.png": "x", + "/src/uploads/file.txt": "y", + }, + entryPaths: []string{"/src/entries/entry.js"}, + options: config.Options{ + Mode: config.ModeBundle, + AbsOutputBase: "/src", + AbsOutputDir: "/out", + AssetPathTemplate: []config.PathTemplate{ + {Data: "", Placeholder: config.ExtPlaceholder}, + {Data: "/", Placeholder: config.NamePlaceholder}, + {Data: "-", Placeholder: config.HashPlaceholder}, + }, + ExtensionToLoader: map[string]config.Loader{ + ".js": config.LoaderJS, + ".png": config.LoaderFile, + ".txt": config.LoaderFile, + }, + }, + }) +} + func TestLoaderFileRelativePathAssetNamesCSS(t *testing.T) { loader_suite.expectBundled(t, bundled{ files: map[string]string{ diff --git a/internal/bundler/linker.go b/internal/bundler/linker.go index 2fa440a5897..d2de5c82514 100644 --- a/internal/bundler/linker.go +++ b/internal/bundler/linker.go @@ -610,12 +610,10 @@ func pathRelativeToOutbase( inputFile *graph.InputFile, options *config.Options, fs fs.FS, - stdExt string, avoidIndex bool, customFilePath string, -) (relDir string, baseName string, baseExt string) { +) (relDir string, baseName string) { relDir = "/" - baseExt = stdExt absPath := inputFile.Source.KeyPath.Text if customFilePath != "" { @@ -3034,14 +3032,14 @@ func (c *linkerContext) computeChunks() []chunkInfo { } } else { // Otherwise, derive the output path from the input path - dir, base, ext = pathRelativeToOutbase( + dir, base = pathRelativeToOutbase( &c.graph.Files[chunk.sourceIndex].InputFile, c.options, c.fs, - stdExt, !file.IsUserSpecifiedEntryPoint(), c.graph.EntryPoints()[chunk.entryPointBit].OutputPath, ) + ext = stdExt } } else { dir = "/" @@ -3051,10 +3049,12 @@ func (c *linkerContext) computeChunks() []chunkInfo { } // Determine the output path template + templateExt := strings.TrimPrefix(ext, ".") template = append(append(make([]config.PathTemplate, 0, len(template)+1), template...), config.PathTemplate{Data: ext}) chunk.finalTemplate = config.SubstituteTemplate(template, config.PathPlaceholders{ Dir: &dir, Name: &base, + Ext: &templateExt, }) } diff --git a/internal/bundler/snapshots/snapshots_loader.txt b/internal/bundler/snapshots/snapshots_loader.txt index 00fbc33935d..512d9959afb 100644 --- a/internal/bundler/snapshots/snapshots_loader.txt +++ b/internal/bundler/snapshots/snapshots_loader.txt @@ -10,6 +10,36 @@ var require_test = __commonJS({ // entry.js console.log(require_test()); +================================================================================ +TestEntryNamesChunkNamesExtPlaceholder +---------- /out/main/js/entry1-L7KI5G7A.js ---------- +import "../../common/js/chunk-XHGYOYUR.js"; + +// src/entries/entry1.js +console.log("entry1"); + +---------- /out/main/js/entry2-KTHKWVT2.js ---------- +import "../../common/js/chunk-XHGYOYUR.js"; + +// src/entries/entry2.js +console.log("entry2"); + +---------- /out/common/js/chunk-XHGYOYUR.js ---------- +// src/lib/shared.js +console.log("shared"); + +---------- /out/main/css/entry1-3JZGIUSL.css ---------- +/* src/entries/entry1.css */ +a:after { + content: "entry1"; +} + +---------- /out/main/css/entry2-NXZBPPIA.css ---------- +/* src/entries/entry2.css */ +a:after { + content: "entry2"; +} + ================================================================================ TestJSXPreserveCapitalLetter ---------- /out.js ---------- @@ -116,6 +146,22 @@ var y_default = "./y-YE5AYNFB.txt"; var x_url = require_x(); console.log(x_url, y_default); +================================================================================ +TestLoaderFileExtPathAssetNamesJS +---------- /out/png/image-LSAMBFUD.png ---------- +x +---------- /out/txt/file-YE5AYNFB.txt ---------- +y +---------- /out/entries/entry.js ---------- +// src/images/image.png +var image_default = "../png/image-LSAMBFUD.png"; + +// src/uploads/file.txt +var file_default = "../txt/file-YE5AYNFB.txt"; + +// src/entries/entry.js +console.log(image_default, file_default); + ================================================================================ TestLoaderFileMultipleNoCollision ---------- /dist/test-J7OMUXO3.txt ---------- diff --git a/internal/config/config.go b/internal/config/config.go index 44734a12984..1b7ea21dd65 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -343,6 +343,10 @@ const ( // A hash of the contents of this file, and the contents and output paths of // all dependencies (except for their hash placeholders) HashPlaceholder + + // The original extension of the file, or the name of the output file + // (e.g. "css", "svg", "png") + ExtPlaceholder ) type PathTemplate struct { @@ -354,6 +358,7 @@ type PathPlaceholders struct { Dir *string Name *string Hash *string + Ext *string } func (placeholders PathPlaceholders) Get(placeholder PathPlaceholder) *string { @@ -364,6 +369,8 @@ func (placeholders PathPlaceholders) Get(placeholder PathPlaceholder) *string { return placeholders.Name case HashPlaceholder: return placeholders.Hash + case ExtPlaceholder: + return placeholders.Ext } return nil } @@ -383,6 +390,8 @@ func TemplateToString(template []PathTemplate) string { sb.WriteString("[name]") case HashPlaceholder: sb.WriteString("[hash]") + case ExtPlaceholder: + sb.WriteString("[ext]") } } return sb.String() diff --git a/pkg/api/api_impl.go b/pkg/api/api_impl.go index 3a9c7e2b7aa..0739dc8f50e 100644 --- a/pkg/api/api_impl.go +++ b/pkg/api/api_impl.go @@ -65,6 +65,10 @@ func validatePathTemplate(template string) []config.PathTemplate { placeholder = config.HashPlaceholder search += len("[hash]") + case strings.HasPrefix(tail, "[ext]"): + placeholder = config.ExtPlaceholder + search += len("[ext]") + default: // Skip past the "[" so we don't find it again search++