fix(transform-shaker, transform): shaker control flow fixes and deferred CJS exports#817
Merged
layershifter merged 9 commits intomainfrom Mar 13, 2026
Merged
Conversation
📊 Bundle size report✅ No changes found |
jurokapsiar
approved these changes
Mar 13, 2026
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…l, and loop test expressions
The shaker was removing scalar child nodes from control flow constructs,
producing invalid syntax:
- `catch(e) {}` → `catch() {}` (invalid, must be `catch(e)` or `catch`)
- `outer: while(…)` → `: while(…)`
- `do {} while(n)` → `do {} while()`
Add these and other control flow children (IfStatement.test,
SwitchStatement.discriminant, ForInStatement, ForOfStatement) to
STRUCTURAL_CHILDREN to prevent removal.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…, not label `export default isPlainObject` was treated as a label (keep), so the identifier wasn't connected to the function declaration in the dependency graph. The shaker removed the function body but kept the export, producing `ReferenceError: isPlainObject is not defined`. Move ExportDefaultDeclaration.declaration from keep to refer so the identifier resolves to its declaration. For inline function/class declarations the handler doesn't fire (they're not Identifier nodes). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…or TS enum IIFEs
oxc-parser wraps `(ThemeName = {})` in a ParenthesizedExpression node, unlike
Babel which stores parentheses as metadata. This caused isLazyInit to fail to
recognize the TypeScript-compiled enum IIFE pattern:
(function(Enum) { ... })(Enum || (Enum = {}));
Without the isLazyInit edge, the IIFE's assignment expression was never
connected to the ExpressionStatement, so the shaker removed the entire IIFE —
leaving the enum variable undefined at runtime.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…toCJS ESM uses live bindings — `export var X` reflects mutations made after the declaration. CJS `exports.X = X` captures the value at assignment time. When a TS-compiled enum IIFE follows `export var Depths;`, the inline `exports.Depths = Depths` captured `undefined` before the IIFE populated it. Deferring all `exports.X = X` from export declarations to the end of the converted module approximates ESM live binding behavior and fixes the `Depths.depth4` undefined error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
822e58c to
c7af071
Compare
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This reverts commit 804dac1.
Co-Authored-By: Claude Opus 4.6 <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.
Summary
transform-shaker
CatchClause.param— shaker was turningcatch(e) {}intocatch() {}(invalid syntax)LabeledStatement.label— shaker was turningouter: while(…)into: while(…)DoWhileStatement.test,WhileStatement.test,IfStatement.test,SwitchStatement.discriminant,ForInStatement.left/right,ForOfStatement.left/right)export default someIdentifiertreated as label instead of reference — shaker was removing the referenced function declarationisLazyInitfailed to recognize(Enum || (Enum = {}))because oxc-parser wraps inParenthesizedExpressiontransform
exports.X = Xassignments to end-of-file inconvertESMtoCJS— fixes TS enum/namespace IIFE patterns where inline assignment capturedundefinedbefore the IIFE populated the variable (e.g.Depths.depth4)Test plan
npx nx test transform-shaker— all tests pass (new tests for catch param, label, export default, IIFE enum preservation)npx nx test transform— all tests pass (new test for deferred export assignment)npx nx test webpack-plugin— all tests pass🤖 Generated with Claude Code