From 8fdb4330a03d156257947f31c4c19b3630ba76fb Mon Sep 17 00:00:00 2001 From: Luke Sheard Date: Tue, 23 Nov 2021 21:07:41 +0000 Subject: [PATCH 1/3] Add ability to pass '[ext]' template to output file name templates --- internal/bundler/bundler.go | 3 +++ internal/bundler/bundler_loader_test.go | 27 +++++++++++++++++++ internal/bundler/linker.go | 3 +++ .../bundler/snapshots/snapshots_loader.txt | 11 ++++++++ internal/config/config.go | 8 ++++++ pkg/api/api_impl.go | 4 +++ 6 files changed, 56 insertions(+) diff --git a/internal/bundler/bundler.go b/internal/bundler/bundler.go index fea150bb225..4f0a4ee8056 100644 --- a/internal/bundler/bundler.go +++ b/internal/bundler/bundler.go @@ -1809,11 +1809,14 @@ func (s *scanner) processScannedFiles() []scannerFile { /* customFilePath */ "", ) + var templateExt = ext[1:] + // Apply the asset path template relPath := config.TemplateToString(config.SubstituteTemplate(s.options.AssetPathTemplate, config.PathPlaceholders{ Dir: &dir, Name: &base, Hash: &hash, + Ext: &templateExt, })) + ext // Optionally add metadata about the file diff --git a/internal/bundler/bundler_loader_test.go b/internal/bundler/bundler_loader_test.go index f8073b77cd6..58ec138f7be 100644 --- a/internal/bundler/bundler_loader_test.go +++ b/internal/bundler/bundler_loader_test.go @@ -469,6 +469,33 @@ 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' + console.log(x) + `, + "/src/images/image.png": "x", + }, + 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, + }, + }, + }) +} + 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 77b312b5aac..8a5f60cbb72 100644 --- a/internal/bundler/linker.go +++ b/internal/bundler/linker.go @@ -3043,11 +3043,14 @@ func (c *linkerContext) computeChunks() []chunkInfo { template = c.options.ChunkPathTemplate } + var templateExt = ext[1:] + // Determine the output path template 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..0a6282b3285 100644 --- a/internal/bundler/snapshots/snapshots_loader.txt +++ b/internal/bundler/snapshots/snapshots_loader.txt @@ -239,6 +239,17 @@ var image_default = "../images/image-LSAMBFUD.png"; // src/entries/entry.js console.log(image_default); +================================================================================ +TestLoaderFileExtPathAssetNamesJS +---------- /out/png/image-LSAMBFUD.png ---------- +x +---------- /out/entries/entry.js ---------- +// src/images/image.png +var image_default = "../png/image-LSAMBFUD.png"; + +// src/entries/entry.js +console.log(image_default); + ================================================================================ TestLoaderFileRelativePathCSS ---------- /out/image-LSAMBFUD.png ---------- diff --git a/internal/config/config.go b/internal/config/config.go index 44734a12984..a3174a7fc34 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -343,6 +343,9 @@ 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 ("css", "svg", "png") + ExtPlaceholder ) type PathTemplate struct { @@ -354,6 +357,7 @@ type PathPlaceholders struct { Dir *string Name *string Hash *string + Ext *string } func (placeholders PathPlaceholders) Get(placeholder PathPlaceholder) *string { @@ -364,6 +368,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 +389,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 f3def8b36dd..76054b01537 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++ From 77a6ea2e458f9f59ee7862a69c89024dbefca2da Mon Sep 17 00:00:00 2001 From: Evan Wallace Date: Sat, 4 Dec 2021 01:23:18 +0000 Subject: [PATCH 2/3] strip unnecessary arg from "pathRelativeToOutbase" --- internal/bundler/bundler.go | 5 ++--- internal/bundler/linker.go | 8 +++----- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/internal/bundler/bundler.go b/internal/bundler/bundler.go index 519af0b1774..1e08cb9e1e4 100644 --- a/internal/bundler/bundler.go +++ b/internal/bundler/bundler.go @@ -1812,11 +1812,10 @@ 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 */ "", ) @@ -1826,7 +1825,7 @@ func (s *scanner) processScannedFiles() []scannerFile { Dir: &dir, Name: &base, Hash: &hash, - })) + ext + })) + originalExt // Optionally add metadata about the file var jsonMetadataChunk string diff --git a/internal/bundler/linker.go b/internal/bundler/linker.go index 2fa440a5897..82ea2984952 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 = "/" From 3dbd62081b776e79879e2c2b4d63ba6e48fae107 Mon Sep 17 00:00:00 2001 From: Evan Wallace Date: Sat, 4 Dec 2021 01:49:00 +0000 Subject: [PATCH 3/3] test all placeholders, fix empty string crash --- internal/bundler/bundler.go | 3 +- internal/bundler/bundler_default_test.go | 32 +++++++++++ internal/bundler/bundler_loader_test.go | 5 +- internal/bundler/linker.go | 3 +- .../bundler/snapshots/snapshots_loader.txt | 57 +++++++++++++++---- internal/config/config.go | 3 +- 6 files changed, 86 insertions(+), 17 deletions(-) diff --git a/internal/bundler/bundler.go b/internal/bundler/bundler.go index a0d7913498f..13d01f9d508 100644 --- a/internal/bundler/bundler.go +++ b/internal/bundler/bundler.go @@ -1820,9 +1820,8 @@ func (s *scanner) processScannedFiles() []scannerFile { /* customFilePath */ "", ) - var templateExt = originalExt[1:] - // Apply the asset path template + templateExt := strings.TrimPrefix(originalExt, ".") relPath := config.TemplateToString(config.SubstituteTemplate(s.options.AssetPathTemplate, config.PathPlaceholders{ Dir: &dir, Name: &base, 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 9a9404720a4..ef59c4afbd4 100644 --- a/internal/bundler/bundler_loader_test.go +++ b/internal/bundler/bundler_loader_test.go @@ -474,9 +474,11 @@ func TestLoaderFileExtPathAssetNamesJS(t *testing.T) { files: map[string]string{ "/src/entries/entry.js": ` import x from '../images/image.png' - console.log(x) + 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{ @@ -491,6 +493,7 @@ func TestLoaderFileExtPathAssetNamesJS(t *testing.T) { ExtensionToLoader: map[string]config.Loader{ ".js": config.LoaderJS, ".png": config.LoaderFile, + ".txt": config.LoaderFile, }, }, }) diff --git a/internal/bundler/linker.go b/internal/bundler/linker.go index 296db25bb53..d2de5c82514 100644 --- a/internal/bundler/linker.go +++ b/internal/bundler/linker.go @@ -3048,9 +3048,8 @@ func (c *linkerContext) computeChunks() []chunkInfo { template = c.options.ChunkPathTemplate } - var templateExt = ext[1:] - // 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, diff --git a/internal/bundler/snapshots/snapshots_loader.txt b/internal/bundler/snapshots/snapshots_loader.txt index 0a6282b3285..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 ---------- @@ -239,17 +285,6 @@ var image_default = "../images/image-LSAMBFUD.png"; // src/entries/entry.js console.log(image_default); -================================================================================ -TestLoaderFileExtPathAssetNamesJS ----------- /out/png/image-LSAMBFUD.png ---------- -x ----------- /out/entries/entry.js ---------- -// src/images/image.png -var image_default = "../png/image-LSAMBFUD.png"; - -// src/entries/entry.js -console.log(image_default); - ================================================================================ TestLoaderFileRelativePathCSS ---------- /out/image-LSAMBFUD.png ---------- diff --git a/internal/config/config.go b/internal/config/config.go index a3174a7fc34..1b7ea21dd65 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -344,7 +344,8 @@ const ( // all dependencies (except for their hash placeholders) HashPlaceholder - // The original extension of the file, or the name of the output file ("css", "svg", "png") + // The original extension of the file, or the name of the output file + // (e.g. "css", "svg", "png") ExtPlaceholder )