Skip to content

fix(bundle): apply node-style CJS interop on all platforms - #34939

Merged
bartlomieju merged 1 commit into
mainfrom
fix/bundle-cjs-interop-browser-platform
Jun 6, 2026
Merged

bartlomieju merged 1 commit into
mainfrom
fix/bundle-cjs-interop-browser-platform

Conversation

@bartlomieju

Copy link
Copy Markdown
Member

deno bundle --platform=browser miscompiled imports of dual CJS/ESM
packages whose ESM entry default-imports a CJS entry that sets
module.exports.__esModule = true. tslib's modules/index.js is the
canonical example. The generated bundle threw at module-init time with
TypeError: Cannot destructure property '__extends' of 'Opt.default' as it is undefined, even though the same code runs fine under deno run
and under --platform=deno.

This is the same root cause as #34524, which was fixed in #34533 by
rewriting esbuild's __toESM interop helper into "node mode" (so the
default import resolves to the whole module.exports rather than to a
synthesized .default that the __esModule marker suppresses). That
fix, however, was gated behind should_replace_require_shim, which only
returns true for --platform=deno, so the browser platform never
received it.

The createRequire shim genuinely is Deno-specific, since it injects an
import from node:module that a browser bundle must not contain. The
node-style CJS interop fix-up is not: it reflects how the source module
resolves its default import of a CJS entry (Node interop semantics, which
is what these packages are authored against), and that is a property of
the importing module, not of the runtime target. This decouples the two
so force_node_cjs_interop runs for every platform while
replace_require_shim stays Deno-only.

The existing cjs_esm_default_interop spec test gains bundle_browser
and bundle_browser_minified variants covering the --platform=browser
path.

Fixes #34837.

PR #34533 fixed broken CJS/ESM default-interop for dual CJS/ESM packages
(e.g. tslib) by rewriting esbuild's __toESM helper into node mode, but
gated that rewrite behind should_replace_require_shim, which only returns
true for --platform=deno. As a result --platform=browser still produced
bundles that threw at module-init time with "Cannot destructure property
'__extends' of 'Opt.default' as it is undefined".

The createRequire shim is genuinely Deno-specific (it injects an import
from node:module), but the node-style CJS interop fix-up is not: it
reflects how the source module resolves its default import of a CJS entry
(Node interop semantics, which is what these packages are authored
against), independent of the runtime target. Decouple the two so
force_node_cjs_interop runs for every platform while replace_require_shim
stays Deno-only.

Fixes #34837.
@bartlomieju
bartlomieju merged commit 181c8e5 into main Jun 6, 2026
137 checks passed
@bartlomieju
bartlomieju deleted the fix/bundle-cjs-interop-browser-platform branch June 6, 2026 08:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

deno bundle question (not sure this is a issue)

1 participant