Skip to content

Commit

Permalink
fix(es/minifier): Remove hack for built-in class names (#8293)
Browse files Browse the repository at this point in the history
**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
kdy1 authored Nov 16, 2023
1 parent f88d6f3 commit 7985e02
Show file tree
Hide file tree
Showing 16 changed files with 447 additions and 198 deletions.
204 changes: 204 additions & 0 deletions crates/swc_ecma_minifier/tests/fixture/next/cryptojs/input.js
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;

}));

/***/
}),


}]);
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"toplevel": true
}
43 changes: 43 additions & 0 deletions crates/swc_ecma_minifier/tests/fixture/next/cryptojs/output.js
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);
}
}
]);
Loading

0 comments on commit 7985e02

Please sign in to comment.