babel / babel/minify

babel minify output has mysterious/broken output for this example

Open
#1,044 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
JavaScript
Stars
4.4k
Forks
217
PR merge metrics
No merged PRs in 30d

Description

**Describe the bug**

Some minified JS code is not functionally equivalent to original, and it produces runtime errors when the minified code is executed. Some extra unexpected string variable is injected into the minified JS code and then later that variable is used as a function which throws.

**To Reproduce**

Minimal code to reproduce the bug

Using package.json like this:

```json
{
"name": "babel-issue",
"version": "1.0.0",
"devDependencies": {
"@babel/core": "^7.14.6",
"@babel/preset-env": "^7.14.7",
"babel-minify": "^0.5.2",
"ts-node": "^10.9.1"
}
}
```

Execute code like this:

```js
const content = `(function() {
var e = YAHOO.util, k = YAHOO.lang, L = YAHOO.env.ua, a = YAHOO.lang.trim, B = {}, F = {}, m = /^t(?:able|d|h)$/i, w = /color$/i, j = window.document, v = j.documentElement, C = "ownerDocument", M = "defaultView", U = "documentElement", S = "compatMode", z = "offsetLeft", o = "offsetTop", T = "offsetParent", x = "parentNode", K = "nodeType", c = "tagName", n = "scrollLeft", H = "scrollTop", p = "getBoundingClientRect", V = "getComputedStyle", y = "currentStyle", l = "CSS1Compat", A = "BackCompat", E = "class", f = "className", i = "", b = " ", R = "(?:^|\\s)", J = "(?= |$)", t = "g", O = "position", D = "fixed", u = "relative", I = "left", N = "top", Q = "medium", P = "borderLeftWidth", q = "borderTopWidth", d = L.opera, h = L.webkit, g = L.gecko, s = L.ie;
e.Dom = {
_getXY: function(W) {
var X, G, Z, ab, Y, aa, ac = Math.round, ad = false;
if (e.Dom._canPosition(W)) {
Z = W[p]();
ab = W[C];
X = e.Dom.getDocumentScrollLeft(ab);
G = e.Dom.getDocumentScrollTop(ab);
ad = [Z[I], Z[N]];
if (Y || aa) {
ad[0] -= aa;
ad[1] -= Y;
}
if ((G || X)) {
ad[0] += X;
ad[1] += G;
}
ad[0] = ac(ad[0]);
ad[1] = ac(ad[1]);
}
return ad;
}
};
})();`;
console.log(new require("babel-minify")(content).code);
```

**Actual Output**

The console will output this:
```
(function(){var b=YAHOO.util,c=YAHOO.lang,e=YAHOO.env.ua,f=YAHOO.lang.trim,a=window.document,i=a.documentElement,j=e.opera,d=e.webkit,h=e.gecko,g=e.ie;b.Dom={_getXY:function(a){var d,e,f,g,h,i,c=Math.round,j="tagName",k=!1;return b.Dom._canPosition(a)&&(f=a.getBoundingClientRect(),g=a.ownerDocument,d=b.Dom.getDocumentScrollLeft(g),e=b.Dom.getDocumentScrollTop(g),k=[f.left,f.top],(h||i)&&(k[0]-=i,k[1]-=h),(e||d)&&(k[0]+=d,k[1]+=e),k[0]=j(k[0]),k[1]=j(k[1])),k}}})();
```

This is prettified like this (but not very pretty)
```js
(function() {
var b = YAHOO.util,
c = YAHOO.lang,
e = YAHOO.env.ua,
f = YAHOO.lang.trim,
a = window.document,
i = a.documentElement,
j = e.opera,
d = e.webkit,
h = e.gecko,
g = e.ie;
b.Dom = {
_getXY: function(a) {
var d, e, f, g, h, i, c = Math.round,
j = "tagName",
k = !1;
return b.Dom._canPosition(a) &&
(f = a.getBoundingClientRect(),
g = a.ownerDocument,
d = b.Dom.getDocumentScrollLeft(g),
e = b.Dom.getDocumentScrollTop(g),
k = [f.left, f.top],
(h || i) &&
(k[0] -= i, k[1] -= h),
(e || d) &&
(k[0] += d, k[1] += e),
k[0] = j(k[0]),
k[1] = j(k[1])),
k;
}
}
})();
```

**Expected Output**

This is my best guess what it should look like instead:
```js
(function() {
var b = YAHOO.util,
c = YAHOO.lang,
e = YAHOO.env.ua,
f = YAHOO.lang.trim,
a = window.document,
i = a.documentElement,
j = e.opera,
d = e.webkit,
h = e.gecko,
g = e.ie;
b.Dom = {
_getXY: function(a) {
var d, e, f, g, h, i, c = Math.round, k = !1;
return b.Dom._canPosition(a) &&
(f = a.getBoundingClientRect(),
g = a.ownerDocument,
d = b.Dom.getDocumentScrollLeft(g),
e = b.Dom.getDocumentScrollTop(g),
k = [f.left, f.top],
(h || i) &&
(k[0] -= i, k[1] -= h),
(e || d) &&
(k[0] += d, k[1] += e),
k[0] = c(k[0]),
k[1] = c(k[1])),
k;
}
}
})();
```
NOTE:
1. The j variable with "tagName" is unexpected
2. Later the js variable is used as a function which throws an exception
3. The function should have been called on the "c" variable which is actually Math.round
4. The example code is not meant to be complete, just a small fragment of the bigger original source file - which I would be happy to provide the original file if necessary.

**Configuration**

All configuration is provided above in the package.json and JS code snippet.

I'm using babel-minify to minify a JS file just as shown above, though in my example I'm reading from constant using only a small JS snippet from the bigger file that has the issue.

**Possible solution**

**Additional context**

As background, I'm trying to replace a google closure implementation that works fine with babel-minify, and mostly works fine - but this one really old JS file is not compressing correctly. I can work around the problem by making minor adjustments to the JS code being minified, which is fine; however, I'd like to know more about the problem. The example JS being minified is from YUI, and I believe the file has been prettified and then minify again - but please just ignore that.

Contributor guide

Open the contributing guide

Research direction

Start with the package.json dependency versions and the supplied JavaScript reproduction, then run babel-minify and compare the generated code with the expected output. Done means the minified fragment keeps Math.round as the called function and does not replace it with the unexpected "tagName" string.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.