Skip to content

Commit 4d997d9

Browse files
committed
fix #3698: yarn pnp edge case with tsconfig.json
1 parent cf42954 commit 4d997d9

4 files changed

Lines changed: 103 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@
6565
})(Foo || {});
6666
```
6767

68+
* Handle Yarn Plug'n'Play edge case with `tsconfig.json` ([#3698](https://github.com/evanw/esbuild/issues/3698))
69+
70+
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.
71+
6872
* Work around issues with Deno 1.31+ ([#3682](https://github.com/evanw/esbuild/issues/3682))
6973

7074
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).

internal/bundler_tests/bundler_tsconfig_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2581,3 +2581,76 @@ func TestTsconfigJsonAsteriskNameCollisionIssue3354(t *testing.T) {
25812581
},
25822582
})
25832583
}
2584+
2585+
// https://github.com/evanw/esbuild/issues/3698
2586+
func TestTsconfigPackageJsonExportsYarnPnP(t *testing.T) {
2587+
tsconfig_suite.expectBundled(t, bundled{
2588+
files: map[string]string{
2589+
"/Users/user/project/packages/app/index.tsx": `
2590+
console.log(<div/>)
2591+
`,
2592+
"/Users/user/project/packages/app/tsconfig.json": `
2593+
{
2594+
"extends": "tsconfigs/config"
2595+
}
2596+
`,
2597+
"/Users/user/project/packages/tsconfigs/package.json": `
2598+
{
2599+
"exports": {
2600+
"./config": "./configs/tsconfig.json"
2601+
}
2602+
}
2603+
`,
2604+
"/Users/user/project/packages/tsconfigs/configs/tsconfig.json": `
2605+
{
2606+
"compilerOptions": {
2607+
"jsxFactory": "success"
2608+
}
2609+
}
2610+
`,
2611+
"/Users/user/project/.pnp.data.json": `
2612+
{
2613+
"packageRegistryData": [
2614+
[
2615+
"app",
2616+
[
2617+
[
2618+
"workspace:packages/app",
2619+
{
2620+
"packageLocation": "./packages/app/",
2621+
"packageDependencies": [
2622+
[
2623+
"tsconfigs",
2624+
"workspace:packages/tsconfigs"
2625+
]
2626+
],
2627+
"linkType": "SOFT"
2628+
}
2629+
]
2630+
]
2631+
],
2632+
[
2633+
"tsconfigs",
2634+
[
2635+
[
2636+
"workspace:packages/tsconfigs",
2637+
{
2638+
"packageLocation": "./packages/tsconfigs/",
2639+
"packageDependencies": [],
2640+
"linkType": "SOFT"
2641+
}
2642+
]
2643+
]
2644+
]
2645+
]
2646+
}
2647+
`,
2648+
},
2649+
entryPaths: []string{"/Users/user/project/packages/app/index.tsx"},
2650+
absWorkingDir: "/Users/user/project",
2651+
options: config.Options{
2652+
Mode: config.ModeBundle,
2653+
AbsOutputFile: "/Users/user/project/out.js",
2654+
},
2655+
})
2656+
}

internal/bundler_tests/snapshots/snapshots_tsconfig.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,12 @@ var both_default = /* @__PURE__ */ R.c(R.F, null, /* @__PURE__ */ R.c("div", nul
396396
// Users/user/project/entry.ts
397397
console.log(factory_default, fragment_default, both_default);
398398

399+
================================================================================
400+
TestTsconfigPackageJsonExportsYarnPnP
401+
---------- /Users/user/project/out.js ----------
402+
// packages/app/index.tsx
403+
console.log(/* @__PURE__ */ success("div", null));
404+
399405
================================================================================
400406
TestTsconfigPaths
401407
---------- /Users/user/project/out.js ----------

internal/resolver/resolver.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1269,6 +1269,26 @@ func (r resolverQuery) parseTSConfigFromSource(source logger.Source, visited map
12691269
}
12701270
goto pnpError
12711271
} else if result.status == pnpSuccess {
1272+
// If Yarn PnP path resolution succeeded, run a custom abbreviated
1273+
// version of node's module resolution algorithm. The Yarn PnP
1274+
// specification says to use node's module resolution algorithm verbatim
1275+
// but that isn't what Yarn actually does. See this for more info:
1276+
// https://github.com/evanw/esbuild/issues/2473#issuecomment-1216774461
1277+
if entries, _, dirErr := r.fs.ReadDirectory(result.pkgDirPath); dirErr == nil {
1278+
if entry, _ := entries.Get("package.json"); entry != nil && entry.Kind(r.fs) == fs.FileEntry {
1279+
// Check the "exports" map
1280+
if packageJSON := r.parsePackageJSON(result.pkgDirPath); packageJSON != nil && packageJSON.exportsMap != nil {
1281+
if absolute, ok, _ := r.esmResolveAlgorithm(result.pkgIdent, "."+result.pkgSubpath, packageJSON, result.pkgDirPath, source.KeyPath.Text); ok {
1282+
base, err := r.parseTSConfig(absolute.Primary.Text, visited)
1283+
if result, shouldReturn := maybeFinishOurSearch(base, err, absolute.Primary.Text); shouldReturn {
1284+
return result
1285+
}
1286+
}
1287+
goto pnpError
1288+
}
1289+
}
1290+
}
1291+
12721292
// Continue with the module resolution algorithm from node.js
12731293
extends = r.fs.Join(result.pkgDirPath, result.pkgSubpath)
12741294
}

0 commit comments

Comments
 (0)