Issue summary
⚠️ Critical: This issue currently breaks physics in the Cannon.js engine
The problem described below is not theoretical — it actively corrupts the physics logic in Cannon.js, causing incorrect collision detection and up to 3–4× performance degradation.
This happens because Rollup’s outdated tree-shaking mechanism removes essential control-flow logic (early returns) used in the SAT algorithm.
The current setup uses:
"rollup": "^4.27.4"
This Rollup version still includes object tree-shaking, a feature known to be problematic because it can silently remove valid runtime code, resulting in broken builds and hard-to-detect logic errors.
What happens
During bundling, Rollup’s object tree-shaking analyzes and removes code it believes has no side effects on exports.
However, in many real-world cases (especially in physics or math-heavy libraries), it mistakenly strips out essential conditional logic.
This leads to invisible functional corruption — code still runs, but with degraded logic or performance.
Example: Physics engine (Cannon.js)
When building with the physics engine cannon.js, the following original function is part of the SAT (Separating Axis Theorem) algorithm:
ConvexPolyhedron.prototype.testSepAxis = function(axis, hullB, posA, quatA, posB, quatB){
var hullA = this;
ConvexPolyhedron.project(hullA, axis, posA, quatA, maxminA);
ConvexPolyhedron.project(hullB, axis, posB, quatB, maxminB);
var maxA = maxminA[0];
var minA = maxminA[1];
var maxB = maxminB[0];
var minB = maxminB[1];
if (maxA < minB || maxB < minA) {
return false; // Separated — no collision
}
var d0 = maxA - minB;
var d1 = maxB - minA;
var depth = d0 < d1 ? d0 : d1;
return depth;
};
This is a performance-critical early-exit check:
if the objects are not intersecting, the function returns early to avoid heavy collision computations.
After Rollup’s tree-shaking, the generated code becomes:
ConvexPolyhedron.prototype.testSepAxis = function(axis, hullB, posA, quatA, posB, quatB){
var hullA = this;
ConvexPolyhedron.project(hullA, axis, posA, quatA, maxminA);
ConvexPolyhedron.project(hullB, axis, posB, quatB, maxminB);
var maxA = maxminA[0];
var minA = maxminA[1];
var maxB = maxminB[0];
var minB = maxminB[1];
var d0 = maxA - minB;
var d1 = maxB - minA;
var depth = d0 < d1 ? d0 : d1;
return depth;
};
Notice that the early return (return false) has been removed.
As a result, every frame performs full collision clipping for all object pairs, causing a 3–4× performance regression.
This behavior occurs regardless of variable names or code formatting, since Rollup analyzes the AST and consistently removes such early exits when it deems them “unused.”
Impact
• Performance degradation: up to 300–400% slower physics computations.
• Silent corruption: logic remains syntactically valid, but semantically broken.
• Non-deterministic builds: the issue may affect different parts of the codebase unpredictably.
This issue is not limited to cannon.js; any library using imperative object-oriented logic (e.g., physics, math, or geometry code) may be affected.
Resolution
- Upgrade Rollup to a version where object tree-shaking is disabled by default.
The issue is resolved in newer releases after PR #5736.
- I have also submitted a pull request to update the rollup version in this project.
Issue summary
The problem described below is not theoretical — it actively corrupts the physics logic in Cannon.js, causing incorrect collision detection and up to 3–4× performance degradation.
This happens because Rollup’s outdated tree-shaking mechanism removes essential control-flow logic (early returns) used in the SAT algorithm.
The current setup uses:
"rollup": "^4.27.4"This Rollup version still includes object tree-shaking, a feature known to be problematic because it can silently remove valid runtime code, resulting in broken builds and hard-to-detect logic errors.
What happens
During bundling, Rollup’s object tree-shaking analyzes and removes code it believes has no side effects on exports.
However, in many real-world cases (especially in physics or math-heavy libraries), it mistakenly strips out essential conditional logic.
This leads to invisible functional corruption — code still runs, but with degraded logic or performance.
Example: Physics engine (Cannon.js)
When building with the physics engine cannon.js, the following original function is part of the SAT (Separating Axis Theorem) algorithm:
This is a performance-critical early-exit check:
if the objects are not intersecting, the function returns early to avoid heavy collision computations.
After Rollup’s tree-shaking, the generated code becomes:
Notice that the early return (return false) has been removed.
As a result, every frame performs full collision clipping for all object pairs, causing a 3–4× performance regression.
This behavior occurs regardless of variable names or code formatting, since Rollup analyzes the AST and consistently removes such early exits when it deems them “unused.”
Impact
This issue is not limited to cannon.js; any library using imperative object-oriented logic (e.g., physics, math, or geometry code) may be affected.
Resolution
The issue is resolved in newer releases after PR #5736.