fix: resolve named CommonJS imports in dev-server bundling ("No matching export")#84
Open
theoryeffects wants to merge 1 commit into
Conversation
The node_modules bundler skips JavaScriptTransformer for non-linker files when advancedOptimizations is false (i.e. during `ng serve`). That transform provides the CommonJS->ESM interop that synthesizes named exports, so skipping it makes `import def, { named } from '<cjs-pkg>'` fail with "No matching export" in dev, while `ng build` (advancedOptimizations=true, transforms every file) works. Keep the dev fast-path for genuine ESM vendor files but not for CommonJS ones, so CJS interop no longer depends on the optimization level.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Fixes #83.
Problem
On the Angular 22 line,
ng servefails while bundling external npm packages when a shared library imports a named export from a CommonJS package — e.g.import dayjs, { isDayjs } from 'dayjs':The production build (
ng build) of the same workspace succeeds. It also reproduces with, for example,quillimporting{ Op, AttributeMap }fromquill-delta.Root cause
In
src/tools/esbuild/node-modules-bundler.ts,advancedOptimizations = !dev, so it isfalseduringng serve. Theangular-linkerplugin'sonLoadthen early-returns for any file that does not need Angular linking:That early return skips
jsTransformer.transformData, which is what performs the CommonJS→ESM interop that synthesizes named exports. So in dev, CommonJS vendor files reach esbuild untransformed and esbuild cannot resolve{ named }imports from them. In productionadvancedOptimizationsistrue, every file is transformed, and the named exports resolve — which is whyng buildworks andng servedoes not.In short: CommonJS-interop correctness is currently coupled to the
advancedOptimizationsoptimization level.Fix
Keep the dev fast-path for genuine ESM vendor files, but do not skip CommonJS files — they still need the interop transform. This preserves fast dev builds (only CommonJS modules pay the transform cost) instead of forcing
advancedOptimizationson in dev:The CommonJS check is a lightweight heuristic; happy to switch it for a more robust detector if you would prefer.
Reproduction
import def, { named } from '<cjs-pkg>'where<cjs-pkg>'s main entry is CommonJS (e.g.dayjs).ng build→ succeeds.ng serve→X [ERROR] No matching export in "node_modules/<cjs-pkg>/..." for import "named".Verification
pnpm buildandpnpm lintpass; the changed file introduces no new lint findings.patch-packagepatch of the same logic) has been running in a real Angular 22 host:ng servebundles the previously failing CommonJS dependencies without error, and the production build is unchanged.Note
@chialab/esbuild-plugin-commonjsis already registered in the same plugin chain but does not resolve these named imports in dev. It may be worth confirming whether it is expected to cover this case; regardless, decoupling the interop fromadvancedOptimizationsfixes the dev/prod discrepancy.