Skip to content

Commit 0286f66

Browse files
committed
suggest enabling missing exports condition (#2163)
1 parent 45c0ab2 commit 0286f66

File tree

4 files changed

+97
-14
lines changed

4 files changed

+97
-14
lines changed

CHANGELOG.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,50 @@
9696
so providing inconsistent metadata for the same path can cause non-determinism.
9797
```
9898

99+
* Suggest enabling a missing condition when `exports` map fails ([#2163](https://github.com/evanw/esbuild/issues/2163))
100+
101+
This release adds another suggestion to the error message that happens when an `exports` map lookup fails if the failure could potentially be fixed by adding a missing condition. Here's what the new error message looks like (which now suggests `--conditions=module` as a possible workaround):
102+
103+
```
104+
✘ [ERROR] Could not resolve "@sentry/electron/main"
105+
106+
index.js:1:24:
107+
1 │ import * as Sentry from '@sentry/electron/main'
108+
╵ ~~~~~~~~~~~~~~~~~~~~~~~
109+
110+
The path "./main" is not currently exported by package "@sentry/electron":
111+
112+
node_modules/@sentry/electron/package.json:8:13:
113+
8 │ "exports": {
114+
╵ ^
115+
116+
None of the conditions provided ("require", "module") match any of the currently active conditions
117+
("browser", "default", "import"):
118+
119+
node_modules/@sentry/electron/package.json:16:14:
120+
16 │ "./main": {
121+
╵ ^
122+
123+
Consider enabling the "module" condition if this package expects it to be enabled. You can use
124+
"--conditions=module" to do that.
125+
126+
node_modules/@sentry/electron/package.json:18:6:
127+
18 │ "module": "./esm/main/index.js"
128+
╵ ~~~~~~~~
129+
130+
Consider using a "require()" call to import this file, which will work because the "require"
131+
condition is supported by this package:
132+
133+
index.js:1:24:
134+
1 │ import * as Sentry from '@sentry/electron/main'
135+
╵ ~~~~~~~~~~~~~~~~~~~~~~~
136+
137+
You can mark the path "@sentry/electron/main" as external to exclude it from the bundle, which
138+
will remove this error.
139+
```
140+
141+
This particular package had an issue where it was using the Webpack-specific `module` condition without providing a `default` condition. It looks like the intent in this case was to use the standard `import` condition instead. This specific change wasn't suggested here because this error message is for package consumers, not package authors.
142+
99143
## 0.14.34
100144

101145
Something went wrong with the publishing script for the previous release. Publishing again.

internal/bundler/bundler_packagejson_test.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1979,10 +1979,12 @@ func TestPackageJsonExportsNoConditionsMatch(t *testing.T) {
19791979
expectedScanLog: `Users/user/project/src/entry.js: ERROR: Could not resolve "pkg1"
19801980
Users/user/project/node_modules/pkg1/package.json: NOTE: The path "." is not currently exported by package "pkg1":
19811981
Users/user/project/node_modules/pkg1/package.json: NOTE: None of the conditions provided ("what") match any of the currently active conditions ("browser", "default", "import"):
1982+
Users/user/project/node_modules/pkg1/package.json: NOTE: Consider enabling the "what" condition if this package expects it to be enabled. You can use 'Conditions: []string{"what"}' to do that.
19821983
NOTE: You can mark the path "pkg1" as external to exclude it from the bundle, which will remove this error.
19831984
Users/user/project/src/entry.js: ERROR: Could not resolve "pkg1/foo.js"
19841985
Users/user/project/node_modules/pkg1/package.json: NOTE: The path "./foo.js" is not currently exported by package "pkg1":
19851986
Users/user/project/node_modules/pkg1/package.json: NOTE: None of the conditions provided ("what") match any of the currently active conditions ("browser", "default", "import"):
1987+
Users/user/project/node_modules/pkg1/package.json: NOTE: Consider enabling the "what" condition if this package expects it to be enabled. You can use 'Conditions: []string{"what"}' to do that.
19861988
NOTE: You can mark the path "pkg1/foo.js" as external to exclude it from the bundle, which will remove this error.
19871989
`,
19881990
})
@@ -2019,12 +2021,12 @@ func TestPackageJsonExportsMustUseRequire(t *testing.T) {
20192021
expectedScanLog: `Users/user/project/src/entry.js: ERROR: Could not resolve "pkg1"
20202022
Users/user/project/node_modules/pkg1/package.json: NOTE: The path "." is not currently exported by package "pkg1":
20212023
Users/user/project/node_modules/pkg1/package.json: NOTE: None of the conditions provided ("require") match any of the currently active conditions ("browser", "default", "import"):
2022-
Users/user/project/src/entry.js: NOTE: Consider using a "require()" call to import this file:
2024+
Users/user/project/src/entry.js: NOTE: Consider using a "require()" call to import this file, which will work because the "require" condition is supported by this package:
20232025
NOTE: You can mark the path "pkg1" as external to exclude it from the bundle, which will remove this error.
20242026
Users/user/project/src/entry.js: ERROR: Could not resolve "pkg1/foo.js"
20252027
Users/user/project/node_modules/pkg1/package.json: NOTE: The path "./foo.js" is not currently exported by package "pkg1":
20262028
Users/user/project/node_modules/pkg1/package.json: NOTE: None of the conditions provided ("require") match any of the currently active conditions ("browser", "default", "import"):
2027-
Users/user/project/src/entry.js: NOTE: Consider using a "require()" call to import this file:
2029+
Users/user/project/src/entry.js: NOTE: Consider using a "require()" call to import this file, which will work because the "require" condition is supported by this package:
20282030
NOTE: You can mark the path "pkg1/foo.js" as external to exclude it from the bundle, which will remove this error.
20292031
`,
20302032
})
@@ -2061,12 +2063,12 @@ func TestPackageJsonExportsMustUseImport(t *testing.T) {
20612063
expectedScanLog: `Users/user/project/src/entry.js: ERROR: Could not resolve "pkg1"
20622064
Users/user/project/node_modules/pkg1/package.json: NOTE: The path "." is not currently exported by package "pkg1":
20632065
Users/user/project/node_modules/pkg1/package.json: NOTE: None of the conditions provided ("import") match any of the currently active conditions ("browser", "default", "require"):
2064-
Users/user/project/src/entry.js: NOTE: Consider using an "import" statement to import this file:
2066+
Users/user/project/src/entry.js: NOTE: Consider using an "import" statement to import this file, which will work because the "import" condition is supported by this package:
20652067
NOTE: You can mark the path "pkg1" as external to exclude it from the bundle, which will remove this error. You can also surround this "require" call with a try/catch block to handle this failure at run-time instead of bundle-time.
20662068
Users/user/project/src/entry.js: ERROR: Could not resolve "pkg1/foo.js"
20672069
Users/user/project/node_modules/pkg1/package.json: NOTE: The path "./foo.js" is not currently exported by package "pkg1":
20682070
Users/user/project/node_modules/pkg1/package.json: NOTE: None of the conditions provided ("import") match any of the currently active conditions ("browser", "default", "require"):
2069-
Users/user/project/src/entry.js: NOTE: Consider using an "import" statement to import this file:
2071+
Users/user/project/src/entry.js: NOTE: Consider using an "import" statement to import this file, which will work because the "import" condition is supported by this package:
20702072
NOTE: You can mark the path "pkg1/foo.js" as external to exclude it from the bundle, which will remove this error. You can also surround this "require" call with a try/catch block to handle this failure at run-time instead of bundle-time.
20712073
`,
20722074
})

internal/resolver/package_json.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -701,8 +701,9 @@ func (status pjStatus) isUndefined() bool {
701701

702702
type pjDebug struct {
703703
// If the status is "pjStatusUndefinedNoConditionsMatch", this is the set of
704-
// conditions that didn't match. This information is used for error messages.
705-
unmatchedConditions []string
704+
// conditions that didn't match, in the order that they were found in the file.
705+
// This information is used for error messages.
706+
unmatchedConditions []logger.Span
706707

707708
// This is the range of the token to use for error messages
708709
token logger.Range
@@ -1056,9 +1057,9 @@ func (r resolverQuery) esmPackageTargetResolve(
10561057
// More information: https://github.com/evanw/esbuild/issues/1484
10571058
target = lastMapEntry.value
10581059
}
1059-
keys := make([]string, len(target.mapData))
1060+
keys := make([]logger.Span, len(target.mapData))
10601061
for i, p := range target.mapData {
1061-
keys[i] = p.key
1062+
keys[i] = logger.Span{Text: p.key, Range: p.keyRange}
10621063
}
10631064
return "", pjStatusUndefinedNoConditionsMatch, pjDebug{
10641065
token: target.firstToken,

internal/resolver/resolver.go

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2052,25 +2052,61 @@ func (r resolverQuery) finalizeImportsExportsResult(
20522052
}
20532053
return strings.Join(quoted, ", ")
20542054
}
2055+
20552056
keys := make([]string, 0, len(conditions))
20562057
for key := range conditions {
20572058
keys = append(keys, key)
20582059
}
20592060
sort.Strings(keys)
2061+
2062+
unmatchedConditions := make([]string, len(debug.unmatchedConditions))
2063+
for i, key := range debug.unmatchedConditions {
2064+
unmatchedConditions[i] = key.Text
2065+
}
2066+
20602067
r.debugMeta.notes = []logger.MsgData{
20612068
tracker.MsgData(importExportMap.root.firstToken,
20622069
fmt.Sprintf("The path %q is not currently exported by package %q:",
20632070
esmPackageSubpath, esmPackageName)),
2071+
20642072
tracker.MsgData(debug.token,
20652073
fmt.Sprintf("None of the conditions provided (%s) match any of the currently active conditions (%s):",
2066-
prettyPrintConditions(debug.unmatchedConditions),
2074+
prettyPrintConditions(unmatchedConditions),
20672075
prettyPrintConditions(keys),
2068-
))}
2076+
)),
2077+
}
2078+
2079+
didSuggestEnablingCondition := false
20692080
for _, key := range debug.unmatchedConditions {
2070-
if key == "import" && (r.kind == ast.ImportRequire || r.kind == ast.ImportRequireResolve) {
2071-
r.debugMeta.suggestionMessage = "Consider using an \"import\" statement to import this file:"
2072-
} else if key == "require" && (r.kind == ast.ImportStmt || r.kind == ast.ImportDynamic) {
2073-
r.debugMeta.suggestionMessage = "Consider using a \"require()\" call to import this file:"
2081+
switch key.Text {
2082+
case "import":
2083+
if r.kind == ast.ImportRequire || r.kind == ast.ImportRequireResolve {
2084+
r.debugMeta.suggestionMessage = "Consider using an \"import\" statement to import this file, " +
2085+
"which will work because the \"import\" condition is supported by this package:"
2086+
}
2087+
2088+
case "require":
2089+
if r.kind == ast.ImportStmt || r.kind == ast.ImportDynamic {
2090+
r.debugMeta.suggestionMessage = "Consider using a \"require()\" call to import this file, " +
2091+
"which will work because the \"require\" condition is supported by this package:"
2092+
}
2093+
2094+
default:
2095+
if !didSuggestEnablingCondition {
2096+
var how string
2097+
switch logger.API {
2098+
case logger.CLIAPI:
2099+
how = fmt.Sprintf("%q", "--conditions="+key.Text)
2100+
case logger.JSAPI:
2101+
how = fmt.Sprintf("\"conditions: ['%s']\"", key.Text)
2102+
case logger.GoAPI:
2103+
how = fmt.Sprintf("'Conditions: []string{%q}'", key.Text)
2104+
}
2105+
r.debugMeta.notes = append(r.debugMeta.notes, tracker.MsgData(key.Range,
2106+
fmt.Sprintf("Consider enabling the %q condition if this package expects it to be enabled. "+
2107+
"You can use %s to do that.", key.Text, how)))
2108+
didSuggestEnablingCondition = true
2109+
}
20742110
}
20752111
}
20762112
}

0 commit comments

Comments
 (0)