Skip to content

Commit 9411fc1

Browse files
committed
fix #1956: entry points use the "import" condition
1 parent 1dd0b94 commit 9411fc1

File tree

4 files changed

+147
-0
lines changed

4 files changed

+147
-0
lines changed

CHANGELOG.md

+8
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22

33
## Unreleased
44

5+
* Prefer the `import` condition for entry points ([#1956](https://github.com/evanw/esbuild/issues/1956))
6+
7+
The `exports` field in `package.json` maps package subpaths to file paths. The mapping can be conditional, which lets it vary in different situations. For example, you can have an `import` condition that applies when the subpath originated from a JS import statement, and a `require` condition that applies when the subpath originated from a JS require call. These are supposed to be mutually exclusive according to the specification: https://nodejs.org/api/packages.html#conditional-exports.
8+
9+
However, there's a situation with esbuild where it's not immediately obvious which one should be applied: when a package name is specified as an entry point. For example, this can happen if you do `esbuild --bundle some-pkg` on the command line. In this situation `some-pkg` does not originate from either a JS import statement or a JS require call. Previously esbuild just didn't apply the `import` or `require` conditions. But that could result in path resolution failure if the package doesn't provide a back-up `default` condition, as is the case with the `is-plain-object` package.
10+
11+
Starting with this release, esbuild will now use the `import` condition in this case. This appears to be how Webpack and Rollup handle this situation so this change makes esbuild consistent with other tools in the ecosystem. Parcel (the other major bundler) just doesn't handle this case at all so esbuild's behavior is not at odds with Parcel's behavior here.
12+
513
* Make parsing of invalid `@keyframes` rules more robust ([#1959](https://github.com/evanw/esbuild/issues/1959))
614

715
This improves esbuild's parsing of certain malformed `@keyframes` rules to avoid them affecting the following rule. This fix only affects invalid CSS files, and does not change any behavior for files containing valid CSS. Here's an example of the fix:

internal/bundler/bundler_packagejson_test.go

+112
Original file line numberDiff line numberDiff line change
@@ -1490,6 +1490,118 @@ func TestPackageJsonExportsDefaultOverImportAndRequire(t *testing.T) {
14901490
})
14911491
}
14921492

1493+
func TestPackageJsonExportsEntryPointImportOverRequire(t *testing.T) {
1494+
packagejson_suite.expectBundled(t, bundled{
1495+
files: map[string]string{
1496+
"/node_modules/pkg/package.json": `
1497+
{
1498+
"exports": {
1499+
"import": "./import.js",
1500+
"require": "./require.js"
1501+
},
1502+
"module": "./module.js",
1503+
"main": "./main.js"
1504+
}
1505+
`,
1506+
"/node_modules/pkg/import.js": `
1507+
console.log('SUCCESS')
1508+
`,
1509+
"/node_modules/pkg/require.js": `
1510+
console.log('FAILURE')
1511+
`,
1512+
"/node_modules/pkg/module.js": `
1513+
console.log('FAILURE')
1514+
`,
1515+
"/node_modules/pkg/main.js": `
1516+
console.log('FAILURE')
1517+
`,
1518+
},
1519+
entryPaths: []string{"pkg"},
1520+
options: config.Options{
1521+
Mode: config.ModeBundle,
1522+
AbsOutputFile: "/out.js",
1523+
},
1524+
})
1525+
}
1526+
1527+
func TestPackageJsonExportsEntryPointRequireOnly(t *testing.T) {
1528+
packagejson_suite.expectBundled(t, bundled{
1529+
files: map[string]string{
1530+
"/node_modules/pkg/package.json": `
1531+
{
1532+
"exports": {
1533+
"require": "./require.js"
1534+
},
1535+
"module": "./module.js",
1536+
"main": "./main.js"
1537+
}
1538+
`,
1539+
"/node_modules/pkg/require.js": `
1540+
console.log('FAILURE')
1541+
`,
1542+
"/node_modules/pkg/module.js": `
1543+
console.log('FAILURE')
1544+
`,
1545+
"/node_modules/pkg/main.js": `
1546+
console.log('FAILURE')
1547+
`,
1548+
},
1549+
entryPaths: []string{"pkg"},
1550+
options: config.Options{
1551+
Mode: config.ModeBundle,
1552+
AbsOutputFile: "/out.js",
1553+
},
1554+
expectedScanLog: `ERROR: Could not resolve "pkg"
1555+
node_modules/pkg/package.json: NOTE: The path "." is not currently exported by package "pkg":
1556+
node_modules/pkg/package.json: NOTE: None of the conditions provided ("require") match any of the currently active conditions ("browser", "default", "import"):
1557+
`,
1558+
})
1559+
}
1560+
1561+
func TestPackageJsonExportsEntryPointModuleOverMain(t *testing.T) {
1562+
packagejson_suite.expectBundled(t, bundled{
1563+
files: map[string]string{
1564+
"/node_modules/pkg/package.json": `
1565+
{
1566+
"module": "./module.js",
1567+
"main": "./main.js"
1568+
}
1569+
`,
1570+
"/node_modules/pkg/module.js": `
1571+
console.log('SUCCESS')
1572+
`,
1573+
"/node_modules/pkg/main.js": `
1574+
console.log('FAILURE')
1575+
`,
1576+
},
1577+
entryPaths: []string{"pkg"},
1578+
options: config.Options{
1579+
Mode: config.ModeBundle,
1580+
AbsOutputFile: "/out.js",
1581+
},
1582+
})
1583+
}
1584+
1585+
func TestPackageJsonExportsEntryPointMainOnly(t *testing.T) {
1586+
packagejson_suite.expectBundled(t, bundled{
1587+
files: map[string]string{
1588+
"/node_modules/pkg/package.json": `
1589+
{
1590+
"main": "./main.js"
1591+
}
1592+
`,
1593+
"/node_modules/pkg/main.js": `
1594+
console.log('SUCCESS')
1595+
`,
1596+
},
1597+
entryPaths: []string{"pkg"},
1598+
options: config.Options{
1599+
Mode: config.ModeBundle,
1600+
AbsOutputFile: "/out.js",
1601+
},
1602+
})
1603+
}
1604+
14931605
func TestPackageJsonExportsBrowser(t *testing.T) {
14941606
packagejson_suite.expectBundled(t, bundled{
14951607
files: map[string]string{

internal/bundler/snapshots/snapshots_packagejson.txt

+18
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,24 @@ TestPackageJsonExportsDefaultOverImportAndRequire
498498
// Users/user/project/node_modules/pkg/default.js
499499
console.log("SUCCESS");
500500

501+
================================================================================
502+
TestPackageJsonExportsEntryPointImportOverRequire
503+
---------- /out.js ----------
504+
// node_modules/pkg/import.js
505+
console.log("SUCCESS");
506+
507+
================================================================================
508+
TestPackageJsonExportsEntryPointMainOnly
509+
---------- /out.js ----------
510+
// node_modules/pkg/main.js
511+
console.log("SUCCESS");
512+
513+
================================================================================
514+
TestPackageJsonExportsEntryPointModuleOverMain
515+
---------- /out.js ----------
516+
// node_modules/pkg/module.js
517+
console.log("SUCCESS");
518+
501519
================================================================================
502520
TestPackageJsonExportsImportOverRequire
503521
---------- /Users/user/project/out.js ----------

internal/resolver/resolver.go

+9
Original file line numberDiff line numberDiff line change
@@ -1679,6 +1679,15 @@ func (r resolverQuery) loadNodeModules(importPath string, dirInfo *dirInfo, forb
16791679
conditions = r.esmConditionsImport
16801680
case ast.ImportRequire, ast.ImportRequireResolve:
16811681
conditions = r.esmConditionsRequire
1682+
case ast.ImportEntryPoint:
1683+
// Treat entry points as imports instead of requires for consistency with
1684+
// Webpack and Rollup. More information:
1685+
//
1686+
// * https://github.com/evanw/esbuild/issues/1956
1687+
// * https://github.com/nodejs/node/issues/41686
1688+
// * https://github.com/evanw/entry-point-resolve-test
1689+
//
1690+
conditions = r.esmConditionsImport
16821691
}
16831692

16841693
// Resolve against the path "/", then join it with the absolute

0 commit comments

Comments
 (0)