Make your libs smaller using private scope in JavaScript

Make your libs smaller using private scope in JavaScript

I've just made an interesting discovery when working on my Bootstrap Tags library when it comes to minified file size. Let me share with you what I found out.

Minification with ESBuild

I'm using ESBuild as a build tool. It's really nice and convenient and supports modern ES6 syntax. It's already doing a great job at minifying stuff , as shown in benchmarks. But when looking at my minified code, I've noticed that all my class properties and methods where not minified. And it makes sense, since in ES6, these are all publicly accessible and part of your class api.

It's possible to get some more minification by using a tool like Terser but I didn't want to add a new tool in my buildchain. There must be another way.

Private scope to the rescue

Was I lazy before? Probably... because I've never bothered so far to use the private class features. But if you want to have nice minified file, you need proper types hints in order to let ESBuild find out which properties and methods can be safely mangled.

class PrivateClass {
  #privateField;
  #privateMethod() {
    return 'hello world';
  }
}

So in the latest version of my library, this is what I did and basically turned most of my properties and methods as private, except for a few ones that I may keep as part of the public api (not even sure if it makes sense to keep them public, but just in case...). Was it worth it? Totally.

  • Before using private scope: 11,4 kb
  • After using private scope: 9,48kb, a 18% improvement!

So for those out there not using TypeScript, there is a very good reason to start using private class features today :-)

UPDATE! Maybe it's not so great after all

Maybe you should consider this carefully for the time being if you are not transpiling your code. Private fields and private methods are well supported, but not as widely as, let's say, JS modules (which is basically my reference level of support at this time).

Also, while the min file will be smaller, the gzipped file difference will be really anecdotical (compressing the same strings in a file is basically what gzip does anyway).

UPDATE 2! Mangling FTW

If you need support for Safari 14.1, private methods are not your friend. Actually, there is an easy alternative to that. Simply replace your # with _ (yes yes I know, your methods are not really private) and with a recent version of esbuild, you can now mangle your properties. It looks like this:

esbuild --mangle-props=^_ --bundle --minify --format=esm --sourcemap mylib.js --outfile=mylib.min.js

And you know what? It's even smaller that the build with private properties because you don't need to declare them at all. This looks like a decent compromise to me.