Repository navigation
Unwrap tsc's interop helpers around builtins; lower re-exports of empty and entry namespaces - #1584
Merged
Merged
Conversation
tsc wraps every CommonJS import in its helpers: `const events_1 =
__importDefault(require("events"))`, `const path =
__importStar(require("path"))`. cjs-tsc-interop.ts reads such bindings of
program modules as plain require bindings, so the helper declarations go
dead, but a builtin module is not a program module: its binding kept the
helpers live, and their probe of the module's top-level `this`
(`(this && this.__importDefault) ||`) failed at load ("property access
through top-level 'this'"). That is the shape of hundreds of tsc-compiled
files in a typical dependency tree.
A builtin carries no `__esModule`, so `events_1.default` is the module and
the namespace copy reads the module's members. When every reference has
that form, a package-file stage now respells the binding as the plain
require() of the builtin and `x.default` as `x`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ry namespace
A bundled module that exports only types keeps `var x_exports = {}` with
no __export call. Its star re-export into the entry,
`__reExport(main, (init_x(), __toCommonJS(x_exports)), module.exports)`,
was left in place because the rewrite only knew namespaces with an export
table, and failed at load on the `module.exports` argument ("the CommonJS
'module' object in this position"). Such a namespace is now an empty
table: the re-export runs the initializer and adds nothing.
Two silent results on the same paths: a member read of a name a module
does not export now answers undefined (`__esModule` true) where it was
refused, and a read through the bundle's own entry namespace inside the
bundle (`(init_index(), __toCommonJS(index_exports)).KIND`) answered
undefined; it now reads the entry's export table.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # tests/harness/npm-cases.ts # tests/harness/npm-static.test.ts
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…re-exports A member read of a name a module does not export answered undefined. Two such names have values on the namespace object: - Object.prototype's members (constructor, toString, __proto__ and the rest), since __toCommonJS builds an ordinary object. - Names a star re-export into the bundle's entry adds: the entry's export table lists only its own exports. Both keep the package refused, as other reads the rewrite cannot follow do.
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #1558.
Summary
tsc's interop helpers around builtin modules. tsc wraps every CommonJS import in its helpers:
const events_1 = __importDefault(require("events")),const path = __importStar(require("path")). For program modules,cjs-tsc-interop.tsreads such a binding as a plain require binding, so the helper declarations go dead. A builtin module is not a program module, though, so its binding kept the helpers live. Their probe of the module's top-levelthis,var __importDefault = (this && this.__importDefault) || …, then failed at load ("property access through top-level 'this'"). That shape appears in hundreds of tsc-compiled files in a typical dependency tree. A builtin carries no__esModule, soevents_1.defaultis the module and the namespace copy reads the module's members. When every reference has that form, a package-file stage now respells the binding as the plainrequire()of the builtin andx.defaultasx. (Dropping the probe instead would be wrong:cjs-tsc-interop.tsrecognizes the helpers by that probe.)Star re-exports of empty namespaces. A bundled module that exports only types keeps
var x_exports = {}with no__exportcall. Its star re-export into the entry,__reExport(main, (init_x(), __toCommonJS(x_exports)), module.exports), was left in place because the rewrite only knew namespaces that have an export table. It then failed at load on themodule.exportsargument ("the CommonJS 'module' object in this position"). Such a namespace is now an empty table: the re-export runs the initializer and adds nothing.Two silent results on the same paths:
undefined(__esModuleanswerstrue), where it was refused.(init_index(), __toCommonJS(index_exports)).KIND) answeredundefined. It now reads the entry's export table.Evidence
tsc-builtin-interop: real tsc 5.6 output (module: commonjs,esModuleInterop) of a class extendingevents.default.EventEmitterand a namespace import ofpath. Output is byte-identical to Node's; before, it failed at load.2595-bundled-entry-namespace: real esbuild 0.27 output where a bundled module reads the entry's own namespace and an empty one. On Load bundled CommonJS dependencies: settled exports, merged requires, semver's tokens, fs.realpath, whole-export members #1558 it printedundefinedwhere Node printslambda.npm-static-tsc-helpers.test.tsruns rewritten modules against their originals under Node, and checks which shapes keep their text;npm-static-bundled-esm.test.tscovers the empty namespace, the types-only star re-export into the entry, and entry namespace reads.modulefence atdist/index.js:119is gone.fs-extra-package(the fs-extra shim's absolute checkout path only).self-hosting-native-driver.test.tspasses (1118 s).pnpm lint,pnpm format:checkandtest:ts7 --baselines-onlypass; only the new fixtures' baselines were added.package-shimssuites and the frontend unit tests pass 1143 of 1144. The one failure,node24-url-authority, comes from the sandbox's Node 24.15.🤖 Generated with Claude Code