Skip to content

Commit

Permalink
fix #3698: yarn pnp edge case with tsconfig.json
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Mar 14, 2024
1 parent cf42954 commit 4d997d9
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 0 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@
})(Foo || {});
```

* Handle Yarn Plug'n'Play edge case with `tsconfig.json` ([#3698](https://github.com/evanw/esbuild/issues/3698))

Previously a `tsconfig.json` file that `extends` another file in a package with an `exports` map failed to work when Yarn's Plug'n'Play resolution was active. This edge case should work now starting with this release.

* Work around issues with Deno 1.31+ ([#3682](https://github.com/evanw/esbuild/issues/3682))

Version 0.20.0 of esbuild changed how the esbuild child process is run in esbuild's API for Deno. Previously it used `Deno.run` but that API is being removed in favor of `Deno.Command`. As part of this change, esbuild is now calling the new `unref` function on esbuild's long-lived child process, which is supposed to allow Deno to exit when your code has finished running even though the child process is still around (previously you had to explicitly call esbuild's `stop()` function to terminate the child process for Deno to be able to exit).
Expand Down
73 changes: 73 additions & 0 deletions internal/bundler_tests/bundler_tsconfig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2581,3 +2581,76 @@ func TestTsconfigJsonAsteriskNameCollisionIssue3354(t *testing.T) {
},
})
}

// https://github.com/evanw/esbuild/issues/3698
func TestTsconfigPackageJsonExportsYarnPnP(t *testing.T) {
tsconfig_suite.expectBundled(t, bundled{
files: map[string]string{
"/Users/user/project/packages/app/index.tsx": `
console.log(<div/>)
`,
"/Users/user/project/packages/app/tsconfig.json": `
{
"extends": "tsconfigs/config"
}
`,
"/Users/user/project/packages/tsconfigs/package.json": `
{
"exports": {
"./config": "./configs/tsconfig.json"
}
}
`,
"/Users/user/project/packages/tsconfigs/configs/tsconfig.json": `
{
"compilerOptions": {
"jsxFactory": "success"
}
}
`,
"/Users/user/project/.pnp.data.json": `
{
"packageRegistryData": [
[
"app",
[
[
"workspace:packages/app",
{
"packageLocation": "./packages/app/",
"packageDependencies": [
[
"tsconfigs",
"workspace:packages/tsconfigs"
]
],
"linkType": "SOFT"
}
]
]
],
[
"tsconfigs",
[
[
"workspace:packages/tsconfigs",
{
"packageLocation": "./packages/tsconfigs/",
"packageDependencies": [],
"linkType": "SOFT"
}
]
]
]
]
}
`,
},
entryPaths: []string{"/Users/user/project/packages/app/index.tsx"},
absWorkingDir: "/Users/user/project",
options: config.Options{
Mode: config.ModeBundle,
AbsOutputFile: "/Users/user/project/out.js",
},
})
}
6 changes: 6 additions & 0 deletions internal/bundler_tests/snapshots/snapshots_tsconfig.txt
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,12 @@ var both_default = /* @__PURE__ */ R.c(R.F, null, /* @__PURE__ */ R.c("div", nul
// Users/user/project/entry.ts
console.log(factory_default, fragment_default, both_default);

================================================================================
TestTsconfigPackageJsonExportsYarnPnP
---------- /Users/user/project/out.js ----------
// packages/app/index.tsx
console.log(/* @__PURE__ */ success("div", null));

================================================================================
TestTsconfigPaths
---------- /Users/user/project/out.js ----------
Expand Down
20 changes: 20 additions & 0 deletions internal/resolver/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -1269,6 +1269,26 @@ func (r resolverQuery) parseTSConfigFromSource(source logger.Source, visited map
}
goto pnpError
} else if result.status == pnpSuccess {
// If Yarn PnP path resolution succeeded, run a custom abbreviated
// version of node's module resolution algorithm. The Yarn PnP
// specification says to use node's module resolution algorithm verbatim
// but that isn't what Yarn actually does. See this for more info:
// https://github.com/evanw/esbuild/issues/2473#issuecomment-1216774461
if entries, _, dirErr := r.fs.ReadDirectory(result.pkgDirPath); dirErr == nil {
if entry, _ := entries.Get("package.json"); entry != nil && entry.Kind(r.fs) == fs.FileEntry {
// Check the "exports" map
if packageJSON := r.parsePackageJSON(result.pkgDirPath); packageJSON != nil && packageJSON.exportsMap != nil {
if absolute, ok, _ := r.esmResolveAlgorithm(result.pkgIdent, "."+result.pkgSubpath, packageJSON, result.pkgDirPath, source.KeyPath.Text); ok {
base, err := r.parseTSConfig(absolute.Primary.Text, visited)
if result, shouldReturn := maybeFinishOurSearch(base, err, absolute.Primary.Text); shouldReturn {
return result
}
}
goto pnpError
}
}
}

// Continue with the module resolution algorithm from node.js
extends = r.fs.Join(result.pkgDirPath, result.pkgSubpath)
}
Expand Down

0 comments on commit 4d997d9

Please sign in to comment.