-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(es/minifier): Remove hack for built-in class names (#8293)
**Description:** Regarding vercel/next.js#55682, I made a mistake while investigating. I assumed it's `swcMinify`-only but it seems like `node-fetch` is fundamentally incompatible with our minification options. I thought `node-fetch` works with terser, but it did not, and it **should not**. But as I thought `terser` works, I assumed that `terser` has a hack for `AbortSignal`. And that's how I fixed `swcMinify: true`. The correct fix is `keep_classnames: true` but it will result in +~10% bundle size bloat. At first, I used the correct way (`keep_classnames: true`), but it resulted in the bundle size bloat, so I mimicked the hack of terser with vercel/next.js#57904. While working on other minification issues, I found that there's no such hack in `terser` and I need to remove the hack in the SWC minifier. The repro in vercel/next.js#55682 does not work with `swcMinify: false`, even with next@14. The problem of minifier and node-fetch was not exploited before `serverMinification: true`. **Related issue:** - brix/crypto-js#415
- Loading branch information
Showing
16 changed files
with
447 additions
and
198 deletions.
There are no files selected for viewing
204 changes: 204 additions & 0 deletions
204
crates/swc_ecma_minifier/tests/fixture/next/cryptojs/input.js
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,204 @@ | ||
(self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([[354], { | ||
|
||
|
||
/***/ 2153: | ||
/***/ (function (module, exports, __webpack_require__) { | ||
|
||
; (function (root, factory) { | ||
if (true) { | ||
// CommonJS | ||
module.exports = exports = factory(__webpack_require__(8249)); | ||
} | ||
else { } | ||
}(this, function (CryptoJS) { | ||
|
||
(function (Math) { | ||
// Shortcuts | ||
var C = CryptoJS; | ||
var C_lib = C.lib; | ||
var WordArray = C_lib.WordArray; | ||
var Hasher = C_lib.Hasher; | ||
var C_algo = C.algo; | ||
|
||
// Initialization and round constants tables | ||
var H = []; | ||
var K = []; | ||
|
||
// Compute constants | ||
(function () { | ||
function isPrime(n) { | ||
var sqrtN = Math.sqrt(n); | ||
for (var factor = 2; factor <= sqrtN; factor++) { | ||
if (!(n % factor)) { | ||
return false; | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
|
||
function getFractionalBits(n) { | ||
return ((n - (n | 0)) * 0x100000000) | 0; | ||
} | ||
|
||
var n = 2; | ||
var nPrime = 0; | ||
while (nPrime < 64) { | ||
if (isPrime(n)) { | ||
if (nPrime < 8) { | ||
H[nPrime] = getFractionalBits(Math.pow(n, 1 / 2)); | ||
} | ||
K[nPrime] = getFractionalBits(Math.pow(n, 1 / 3)); | ||
|
||
nPrime++; | ||
} | ||
|
||
n++; | ||
} | ||
}()); | ||
|
||
// Reusable object | ||
var W = []; | ||
|
||
/** | ||
* SHA-256 hash algorithm. | ||
*/ | ||
var SHA256 = C_algo.SHA256 = Hasher.extend({ | ||
_doReset: function () { | ||
this._hash = new WordArray.init(H.slice(0)); | ||
}, | ||
|
||
_doProcessBlock: function (M, offset) { | ||
// Shortcut | ||
var H = this._hash.words; | ||
|
||
// Working variables | ||
var a = H[0]; | ||
var b = H[1]; | ||
var c = H[2]; | ||
var d = H[3]; | ||
var e = H[4]; | ||
var f = H[5]; | ||
var g = H[6]; | ||
var h = H[7]; | ||
|
||
// Computation | ||
for (var i = 0; i < 64; i++) { | ||
if (i < 16) { | ||
W[i] = M[offset + i] | 0; | ||
} else { | ||
var gamma0x = W[i - 15]; | ||
var gamma0 = ((gamma0x << 25) | (gamma0x >>> 7)) ^ | ||
((gamma0x << 14) | (gamma0x >>> 18)) ^ | ||
(gamma0x >>> 3); | ||
|
||
var gamma1x = W[i - 2]; | ||
var gamma1 = ((gamma1x << 15) | (gamma1x >>> 17)) ^ | ||
((gamma1x << 13) | (gamma1x >>> 19)) ^ | ||
(gamma1x >>> 10); | ||
|
||
W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16]; | ||
} | ||
|
||
var ch = (e & f) ^ (~e & g); | ||
var maj = (a & b) ^ (a & c) ^ (b & c); | ||
|
||
var sigma0 = ((a << 30) | (a >>> 2)) ^ ((a << 19) | (a >>> 13)) ^ ((a << 10) | (a >>> 22)); | ||
var sigma1 = ((e << 26) | (e >>> 6)) ^ ((e << 21) | (e >>> 11)) ^ ((e << 7) | (e >>> 25)); | ||
|
||
var t1 = h + sigma1 + ch + K[i] + W[i]; | ||
var t2 = sigma0 + maj; | ||
|
||
h = g; | ||
g = f; | ||
f = e; | ||
e = (d + t1) | 0; | ||
d = c; | ||
c = b; | ||
b = a; | ||
a = (t1 + t2) | 0; | ||
} | ||
|
||
// Intermediate hash value | ||
H[0] = (H[0] + a) | 0; | ||
H[1] = (H[1] + b) | 0; | ||
H[2] = (H[2] + c) | 0; | ||
H[3] = (H[3] + d) | 0; | ||
H[4] = (H[4] + e) | 0; | ||
H[5] = (H[5] + f) | 0; | ||
H[6] = (H[6] + g) | 0; | ||
H[7] = (H[7] + h) | 0; | ||
}, | ||
|
||
_doFinalize: function () { | ||
// Shortcuts | ||
var data = this._data; | ||
var dataWords = data.words; | ||
|
||
var nBitsTotal = this._nDataBytes * 8; | ||
var nBitsLeft = data.sigBytes * 8; | ||
|
||
// Add padding | ||
dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); | ||
dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000); | ||
dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal; | ||
data.sigBytes = dataWords.length * 4; | ||
|
||
// Hash final blocks | ||
this._process(); | ||
|
||
// Return final computed hash | ||
return this._hash; | ||
}, | ||
|
||
clone: function () { | ||
var clone = Hasher.clone.call(this); | ||
clone._hash = this._hash.clone(); | ||
|
||
return clone; | ||
} | ||
}); | ||
|
||
/** | ||
* Shortcut function to the hasher's object interface. | ||
* | ||
* @param {WordArray|string} message The message to hash. | ||
* | ||
* @return {WordArray} The hash. | ||
* | ||
* @static | ||
* | ||
* @example | ||
* | ||
* var hash = CryptoJS.SHA256('message'); | ||
* var hash = CryptoJS.SHA256(wordArray); | ||
*/ | ||
C.SHA256 = Hasher._createHelper(SHA256); | ||
|
||
/** | ||
* Shortcut function to the HMAC's object interface. | ||
* | ||
* @param {WordArray|string} message The message to hash. | ||
* @param {WordArray|string} key The secret key. | ||
* | ||
* @return {WordArray} The HMAC. | ||
* | ||
* @static | ||
* | ||
* @example | ||
* | ||
* var hmac = CryptoJS.HmacSHA256(message, key); | ||
*/ | ||
C.HmacSHA256 = Hasher._createHmacHelper(SHA256); | ||
}(Math)); | ||
|
||
|
||
return CryptoJS.SHA256; | ||
|
||
})); | ||
|
||
/***/ | ||
}), | ||
|
||
|
||
}]); |
3 changes: 3 additions & 0 deletions
3
crates/swc_ecma_minifier/tests/fixture/next/cryptojs/mangle.json
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"toplevel": true | ||
} |
43 changes: 43 additions & 0 deletions
43
crates/swc_ecma_minifier/tests/fixture/next/cryptojs/output.js
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
(self.webpackChunk_N_E = self.webpackChunk_N_E || []).push([ | ||
[ | ||
354 | ||
], | ||
{ | ||
2153: function(e, r, t) { | ||
var s, n, a, o, i, h, c, l, _, f; | ||
e.exports = (s = t(8249), n = Math, o = (a = s.lib).WordArray, i = a.Hasher, h = s.algo, c = [], l = [], function() { | ||
function e(e) { | ||
return (e - (0 | e)) * 0x100000000 | 0; | ||
} | ||
for(var r = 2, t = 0; t < 64;)(function(e) { | ||
for(var r = n.sqrt(e), t = 2; t <= r; t++)if (!(e % t)) return !1; | ||
return !0; | ||
})(r) && (t < 8 && (c[t] = e(n.pow(r, 0.5))), l[t] = e(n.pow(r, 1 / 3)), t++), r++; | ||
}(), _ = [], f = h.SHA256 = i.extend({ | ||
_doReset: function() { | ||
this._hash = new o.init(c.slice(0)); | ||
}, | ||
_doProcessBlock: function(e, r) { | ||
for(var t = this._hash.words, s = t[0], n = t[1], a = t[2], o = t[3], i = t[4], h = t[5], c = t[6], f = t[7], u = 0; u < 64; u++){ | ||
if (u < 16) _[u] = 0 | e[r + u]; | ||
else { | ||
var p = _[u - 15], H = (p << 25 | p >>> 7) ^ (p << 14 | p >>> 18) ^ p >>> 3, d = _[u - 2], v = (d << 15 | d >>> 17) ^ (d << 13 | d >>> 19) ^ d >>> 10; | ||
_[u] = H + _[u - 7] + v + _[u - 16]; | ||
} | ||
var w = i & h ^ ~i & c, k = s & n ^ s & a ^ n & a, A = (s << 30 | s >>> 2) ^ (s << 19 | s >>> 13) ^ (s << 10 | s >>> 22), g = f + ((i << 26 | i >>> 6) ^ (i << 21 | i >>> 11) ^ (i << 7 | i >>> 25)) + w + l[u] + _[u], y = A + k; | ||
f = c, c = h, h = i, i = o + g | 0, o = a, a = n, n = s, s = g + y | 0; | ||
} | ||
t[0] = t[0] + s | 0, t[1] = t[1] + n | 0, t[2] = t[2] + a | 0, t[3] = t[3] + o | 0, t[4] = t[4] + i | 0, t[5] = t[5] + h | 0, t[6] = t[6] + c | 0, t[7] = t[7] + f | 0; | ||
}, | ||
_doFinalize: function() { | ||
var e = this._data, r = e.words, t = 8 * this._nDataBytes, s = 8 * e.sigBytes; | ||
return r[s >>> 5] |= 0x80 << 24 - s % 32, r[(s + 64 >>> 9 << 4) + 14] = n.floor(t / 0x100000000), r[(s + 64 >>> 9 << 4) + 15] = t, e.sigBytes = 4 * r.length, this._process(), this._hash; | ||
}, | ||
clone: function() { | ||
var e = i.clone.call(this); | ||
return e._hash = this._hash.clone(), e; | ||
} | ||
}), s.SHA256 = i._createHelper(f), s.HmacSHA256 = i._createHmacHelper(f), s.SHA256); | ||
} | ||
} | ||
]); |
Oops, something went wrong.