diff --git a/CHANGELOG.md b/CHANGELOG.md index f97ad32c626..59de931f2e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -93,6 +93,10 @@ However, the compilation had a subtle bug where the automatically-generated function-level symbols for multible hoisted block-level function declarations in the same block a sloppy-mode context were generated in a random order if the output was in strict mode, which could be the case if TypeScript's `alwaysStrict` setting was set to true. This lead to non-determinism in the output as the minifier would randomly exchange the generated names for these symbols on different runs. This bug has been fixed by sorting the keys of the unordered map before iterating over them. +* Fix subpath imports with Yarn PnP ([#2545](https://github.com/evanw/esbuild/issues/2545)) + + Node has a little-used feature called [subpath imports](https://nodejs.org/api/packages.html#subpath-imports) which are package-internal imports that start with `#` and that go through the `imports` map in `package.json`. Previously esbuild had a bug that caused esbuild to not handle these correctly in packages installed via Yarn's "Plug'n'Play" installation strategy. The problem was that subpath imports were being checked after Yarn PnP instead of before. This release reorders these checks, which should allow subpath imports to work in this case. + ## 0.15.7 * Add `--watch=forever` to allow esbuild to never terminate ([#1511](https://github.com/evanw/esbuild/issues/1511), [#1885](https://github.com/evanw/esbuild/issues/1885)) diff --git a/internal/resolver/resolver.go b/internal/resolver/resolver.go index fce281dce20..6814e7b2897 100644 --- a/internal/resolver/resolver.go +++ b/internal/resolver/resolver.go @@ -1999,6 +1999,17 @@ func (r resolverQuery) loadNodeModules(importPath string, dirInfo *dirInfo, forb } } + // Find the parent directory with the "package.json" file + dirInfoPackageJSON := dirInfo + for dirInfoPackageJSON != nil && dirInfoPackageJSON.packageJSON == nil { + dirInfoPackageJSON = dirInfoPackageJSON.parent + } + + // Check for subpath imports: https://nodejs.org/api/packages.html#subpath-imports + if dirInfoPackageJSON != nil && strings.HasPrefix(importPath, "#") && !forbidImports && dirInfoPackageJSON.packageJSON.importsMap != nil { + return r.loadPackageImports(importPath, dirInfoPackageJSON) + } + // If Yarn PnP is active, use it to find the package if r.pnpManifest != nil { if result := r.resolveToUnqualified(importPath, dirInfo.absPath, r.pnpManifest); result.status == pnpError { @@ -2042,17 +2053,6 @@ func (r resolverQuery) loadNodeModules(importPath string, dirInfo *dirInfo, forb } } - // Find the parent directory with the "package.json" file - dirInfoPackageJSON := dirInfo - for dirInfoPackageJSON != nil && dirInfoPackageJSON.packageJSON == nil { - dirInfoPackageJSON = dirInfoPackageJSON.parent - } - - // Check for subpath imports: https://nodejs.org/api/packages.html#subpath-imports - if dirInfoPackageJSON != nil && strings.HasPrefix(importPath, "#") && !forbidImports && dirInfoPackageJSON.packageJSON.importsMap != nil { - return r.loadPackageImports(importPath, dirInfoPackageJSON) - } - // Try to parse the package name using node's ESM-specific rules esmPackageName, esmPackageSubpath, esmOK := esmParsePackageName(importPath) if r.debugLogs != nil && esmOK { diff --git a/require/yarnpnp/in.mjs b/require/yarnpnp/in.mjs index ca9050b6635..b2654172350 100644 --- a/require/yarnpnp/in.mjs +++ b/require/yarnpnp/in.mjs @@ -14,6 +14,9 @@ if (!d3.utcDay) throw '❌ d3-time' import * as mm from 'mime' if (mm.default.getType('txt') !== 'text/plain') throw '❌ mime' +import * as ajv from 'aws-jwt-verify' +if (!ajv.CognitoJwtVerifier) throw '❌ aws-jwt-verify' + import * as foo from 'foo' if (foo.default !== 'foo') throw '❌ foo' diff --git a/scripts/test-yarnpnp.js b/scripts/test-yarnpnp.js index 3c776c2c275..e68dad4d00a 100644 --- a/scripts/test-yarnpnp.js +++ b/scripts/test-yarnpnp.js @@ -38,7 +38,7 @@ function reinstallYarnIfNeeded() { } const rc = fs.readFileSync(path.join(rootDir, '.yarnrc.yml'), 'utf8') - fs.writeFileSync(path.join(rootDir, '.yarnrc.yml'), `pnpIgnorePatterns: ["./bar/**"]\n` + rc) + fs.writeFileSync(path.join(rootDir, '.yarnrc.yml'), `pnpEnableEsmLoader: true\npnpIgnorePatterns: ["./bar/**"]\n` + rc) run('yarn install') }