Skip to content

Commit 7bf440d

Browse files
committed
fix #2730: alias now strips a trailing slash
1 parent b0a82d3 commit 7bf440d

File tree

5 files changed

+26
-2
lines changed

5 files changed

+26
-2
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@
2626
}
2727
```
2828

29+
* The alias feature now strips a trailing slash ([#2730](https://github.com/evanw/esbuild/issues/2730))
30+
31+
People sometimes add a trailing slash to the name of one of node's built-in modules to force node to import from the file system instead of importing the built-in module. For example, importing `util` imports node's built-in module called `util` but importing `util/` tries to find a package called `util` on the file system. Previously attempting to use esbuild's package alias feature to replace imports to `util` with a specific file would fail because the file path would also gain a trailing slash (e.g. mapping `util` to `./file.js` turned `util/` into `./file.js/`). With this release, esbuild will now omit the path suffix if it's a single trailing slash, which should now allow you to successfully apply aliases to these import paths.
32+
2933
## 0.16.6
3034

3135
* Do not mark subpath imports as external with `--packages=external` ([#2741](https://github.com/evanw/esbuild/issues/2741))

internal/bundler/bundler.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,7 @@ func ResolveFailureErrorTextSuggestionNotes(
548548
}
549549
hint := ""
550550

551-
if resolver.IsPackagePath(path) {
551+
if resolver.IsPackagePath(path) && !fs.IsAbs(path) {
552552
hint = fmt.Sprintf("You can mark the path %q as external to exclude it from the bundle, which will remove this error.", path)
553553
if kind == ast.ImportRequire {
554554
hint += " You can also surround this \"require\" call with a try/catch block to handle this failure at run-time instead of bundle-time."

internal/bundler/bundler_default_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6924,6 +6924,7 @@ func TestPackageAlias(t *testing.T) {
69246924
import "@abs-path/pkg6"
69256925
import "@abs-path/pkg7/foo"
69266926
import "@scope-only/pkg8"
6927+
import "slash/"
69276928
`,
69286929
"/nested3/index.js": `import "pkg3"`,
69296930
"/nested3/node_modules/alias3/index.js": `test failure`,
@@ -6935,6 +6936,7 @@ func TestPackageAlias(t *testing.T) {
69356936
"/alias6/dir/index.js": `console.log(6)`,
69366937
"/alias7/dir/foo/index.js": `console.log(7)`,
69376938
"/alias8/dir/pkg8/index.js": `console.log(8)`,
6939+
"/alias9/some/file.js": `console.log(9)`,
69386940
},
69396941
entryPaths: []string{"/entry.js"},
69406942
options: config.Options{
@@ -6949,6 +6951,7 @@ func TestPackageAlias(t *testing.T) {
69496951
"@abs-path/pkg6": `/alias6/dir`,
69506952
"@abs-path/pkg7": `/alias7/dir`,
69516953
"@scope-only": "/alias8/dir",
6954+
"slash": "/alias9/some/file.js",
69526955
},
69536956
},
69546957
})

internal/bundler/snapshots/snapshots_loader.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1528,6 +1528,9 @@ console.log(7);
15281528
// alias8/dir/pkg8/index.js
15291529
console.log(8);
15301530

1531+
// alias9/some/file.js
1532+
console.log(9);
1533+
15311534
================================================================================
15321535
TestRequireCustomExtensionBase64
15331536
---------- /out.js ----------

internal/resolver/resolver.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,21 @@ func (rr *resolver) Resolve(sourceDir string, importPath string, kind ast.Import
313313
// when using Yarn PnP because Yarn PnP doesn't allow nested packages
314314
// to "reach outside" of their normal dependency lists.
315315
sourceDir = r.fs.Cwd()
316-
debugMeta.ModifiedImportPath = value + importPath[len(key):]
316+
if tail := importPath[len(key):]; tail != "/" {
317+
// Don't include the trailing characters if they are equal to a
318+
// single slash. This comes up because you can abuse this quirk of
319+
// node's path resolution to force node to load the package from the
320+
// file system instead of as a built-in module. For example, "util"
321+
// is node's built-in module while "util/" is one on the file system.
322+
// Leaving the trailing slash in place causes problems for people:
323+
// https://github.com/evanw/esbuild/issues/2730. It should be ok to
324+
// always strip the trailing slash even when using the alias feature
325+
// to swap one package for another (except when you swap a reference
326+
// to one built-in node module with another but really why would you
327+
// do that).
328+
value += tail
329+
}
330+
debugMeta.ModifiedImportPath = value
317331
if r.debugLogs != nil {
318332
r.debugLogs.addNote(fmt.Sprintf(" Matched with alias from %q to %q", key, value))
319333
r.debugLogs.addNote(fmt.Sprintf(" Modified import path from %q to %q", importPath, debugMeta.ModifiedImportPath))

0 commit comments

Comments
 (0)