From f42ca4a39c4b956baddcc6d48253ed875c1d8a8b Mon Sep 17 00:00:00 2001 From: Evan Wallace Date: Wed, 28 Dec 2022 00:33:21 +0000 Subject: [PATCH] allow loaders for extensionless files --- internal/bundler/bundler.go | 19 +++++++--- internal/bundler_tests/bundler_loader_test.go | 38 +++++++++++++++++++ .../snapshots/snapshots_loader.txt | 16 ++++++++ pkg/api/api_impl.go | 2 +- 4 files changed, 68 insertions(+), 7 deletions(-) diff --git a/internal/bundler/bundler.go b/internal/bundler/bundler.go index 3b7321ee31e..1fd04c24fff 100644 --- a/internal/bundler/bundler.go +++ b/internal/bundler/bundler.go @@ -1012,15 +1012,22 @@ func loaderFromFileExtension(extensionToLoader map[string]config.Loader, base st // Pick the loader with the longest matching extension. So if there's an // extension for ".css" and for ".module.css", we want to match the one for // ".module.css" before the one for ".css". - for { - i := strings.IndexByte(base, '.') - if i == -1 { - break + if i := strings.IndexByte(base, '.'); i != -1 { + for { + if loader, ok := extensionToLoader[base[i:]]; ok { + return loader + } + base = base[i+1:] + i = strings.IndexByte(base, '.') + if i == -1 { + break + } } - if loader, ok := extensionToLoader[base[i:]]; ok { + } else { + // If there's no extension, explicitly check for an extensionless loader + if loader, ok := extensionToLoader[""]; ok { return loader } - base = base[i+1:] } return config.LoaderNone } diff --git a/internal/bundler_tests/bundler_loader_test.go b/internal/bundler_tests/bundler_loader_test.go index c7548be73c4..99c2471a526 100644 --- a/internal/bundler_tests/bundler_loader_test.go +++ b/internal/bundler_tests/bundler_loader_test.go @@ -1337,3 +1337,41 @@ func TestEmptyLoaderCSS(t *testing.T) { }, }) } + +func TestExtensionlessLoaderJS(t *testing.T) { + loader_suite.expectBundled(t, bundled{ + files: map[string]string{ + "/entry.js": ` + import './what' + `, + "/what": `foo()`, + }, + entryPaths: []string{"/entry.js"}, + options: config.Options{ + Mode: config.ModeBundle, + ExtensionToLoader: map[string]config.Loader{ + ".js": config.LoaderJS, + "": config.LoaderJS, + }, + }, + }) +} + +func TestExtensionlessLoaderCSS(t *testing.T) { + loader_suite.expectBundled(t, bundled{ + files: map[string]string{ + "/entry.css": ` + @import './what'; + `, + "/what": `.foo { color: red }`, + }, + entryPaths: []string{"/entry.css"}, + options: config.Options{ + Mode: config.ModeBundle, + ExtensionToLoader: map[string]config.Loader{ + ".css": config.LoaderCSS, + "": config.LoaderCSS, + }, + }, + }) +} diff --git a/internal/bundler_tests/snapshots/snapshots_loader.txt b/internal/bundler_tests/snapshots/snapshots_loader.txt index 446ab633a0f..21cd2b3bca1 100644 --- a/internal/bundler_tests/snapshots/snapshots_loader.txt +++ b/internal/bundler_tests/snapshots/snapshots_loader.txt @@ -173,6 +173,22 @@ console.log(ns, import_c.default, void 0); } } +================================================================================ +TestExtensionlessLoaderCSS +---------- entry.css ---------- +/* what */ +.foo { + color: red; +} + +/* entry.css */ + +================================================================================ +TestExtensionlessLoaderJS +---------- entry.js ---------- +// what +foo(); + ================================================================================ TestJSXAutomaticNoNameCollision ---------- /out.js ---------- diff --git a/pkg/api/api_impl.go b/pkg/api/api_impl.go index 96dea017f44..5b1aa2dc47d 100644 --- a/pkg/api/api_impl.go +++ b/pkg/api/api_impl.go @@ -545,7 +545,7 @@ func validateLoaders(log logger.Log, loaders map[string]Loader) map[string]confi result := bundler.DefaultExtensionToLoaderMap() if loaders != nil { for ext, loader := range loaders { - if !isValidExtension(ext) { + if ext != "" && !isValidExtension(ext) { log.AddError(nil, logger.Range{}, fmt.Sprintf("Invalid file extension: %q", ext)) } result[ext] = validateLoader(loader)