parcel: Parcel 2 lets babel private class polyfill bloat everything so much that an unused class adds *400 BYTES* WITH A PURE COMMENT

🐛 bug report

Sometimes modules have sideeffects and usually terser eats them. If it doesn’t, I can add a pure comment and then it eats them.

However the babel private class polyfill is so huge and weird (it’s maybe less weird in loose mode but loose mode nearly produces equally huge outputs) that terser no longer removes all side effects.

Well, terser removes all side effects of my original code, but the babel transform causes side effects which terser doesn’t remove.

I just noticed it’s even worse: the babel artifacts are still in the output if there’s just a class with private properties in a module, even if it’s not even referenced from anywhere - try uncommenting everything before function used_export in module.ts

🎛 Configuration (.babelrc, package.json, cli command)

Please see attached .zip file.

🤔 Expected Behavior

!async function(){console.log("hi")}();

😯 Current Behavior

!function(){var e,t,n={},r={};t=r=function(e,t){return t.get?t.get.call(e):t.value},r.default=t,r.__esModule=true;var u,a=r,o={};u=o=function(e,t,n){if(!t.has(e))throw new TypeError("attempted to "+n+" private field on non-instance");return t.get(e)},o.default=u,o.__esModule=true;var l=o;e=n=function(e,t){var n=l(e,t,"get");return a(e,n)},n.default=e,n.__esModule=true;new WeakMap,new WeakSet;!async function(){console.log("hi")}()}();

(beautified for your convenience:

! function() {
  var e, t, n = {},
    r = {};
  t = r = function(e, t) {
    return t.get ? t.get.call(e) : t.value
  }, r.default = t, r.__esModule = true;
  var u, a = r,
    o = {};
  u = o = function(e, t, n) {
    if (!t.has(e)) throw new TypeError("attempted to " + n + " private field on non-instance");
    return t.get(e)
  }, o.default = u, o.__esModule = true;
  var l = o;
  e = n = function(e, t) {
    var n = l(e, t, "get");
    return a(e, n)
  }, n.default = e, n.__esModule = true;
  new WeakMap, new WeakSet;
  !async function() {
    console.log("hi")
  }()
}();

)

💁 Possible Solution

Add a pure comment before some function call of babel’s output so that terser nukes it all.

🔦 Context

I want smaller output files.

💻 Code Sample

parcel-babel-bloat.zip

🌍 Your Environment

Software Version(s)
Parcel 2.0.0-nightly.635+f5962737
Node v15.13.0
npm/Yarn 7.7.6
Operating System macOS 10.15.7 (19H524)

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 29 (15 by maintainers)

Most upvoted comments

Cross-linking it here: I opened a PR in the Babel repo to add the pure annotations (https://github.com/babel/babel/pull/13194)

Thanks to the efforts of @alexlamsl, a yet to be released version of uglify-js has improved alias analysis and can now DCE the unused private class commonjs helpers, WeakMap, and WeakSet without modification to the original source code or babel:

$ cat parcel_bundle_6116.js | uglify-js -b
!function() {
    var e, t, n = {}, r = {};
    t = r = function(e, t) {
        return t.get ? t.get.call(e) : t.value;
    }, r.default = t, r.__esModule = true;
    var u, a = r, o = {};
    u = o = function(e, t, n) {
        if (!t.has(e)) throw new TypeError("attempted to " + n + " private field on non-instance");
        return t.get(e);
    }, o.default = u, o.__esModule = true;
    var l = o;
    e = n = function(e, t) {
        var n = l(e, t, "get");
        return a(e, n);
    }, n.default = e, n.__esModule = true;
    new WeakMap(), new WeakSet();
    !async function() {
        console.log("hi");
    }();
}();

Some non-default uglify-js minify options are necessary to achieve a smaller bundle size:

$ cat parcel_bundle_6116.js | uglify-js -mc passes=2
new WeakMap,new WeakSet,async function(){console.log("hi")}();

The uglify-js unsafecompress option is needed to remove unused built-in JS classes:

$ cat parcel_bundle_6116.js | uglify-js -mc passes=2,unsafe
!async function(){console.log("hi")}();

Parcel is great but has a bunch of issues and someone needs to pay to fix them.

That’s true! The general expectation for free open source projects is that the “someone who pays for maintainance” are the users (individuals, or even better companies since they can pay more) of the project. Parcel accepts donations at https://opencollective.com/parcel!

Should be fixed in in Babel 7.14.0