Hacker News new | ask | show | jobs
by dheera 1133 days ago
Why are we still minifying JavaScript? Is it only for obfuscation?

State-of-the-art HTTP servers already do a pretty damn good job gzipping stuff on the fly, do we need this garbage?

If it is for obfuscation, fine, can we just call it that?

4 comments

You can shrink transmitted sizes even further by using minification on top of transport compression. That nets me ~25% reduction in size compared to compression without minification, in practice, and those kinds of gains add up, especially at the tail end of page load times.
Not to mention, you can get better compression with some pre-compression levels that are hard to match with the best on the fly, often getting another 10% or more on size. It all adds up.

There are some Steve Souders books on optimization that are pretty good and still pretty relevant.

If you minify, aren't you increasing the overall information entropy, and thereby decreasing the amount that can be gained from compression? I'm sure overall there's still a net gain but I wonder where the point of inflection is.
Depends on the algorithm... the ones used with http typically have less overhead for decompression than compression.

If you mean code minification, that can depend, but in general with tree shaking it shouldn't be slower, typically. The computer doesn't care if a variable is aa or myDescriptiveVariableName.

In my experience things kind of balance out, and you end up with negligible compression gains after compression. On the other hand, it also affects the time it takes for the browser / js engine to parse and execute the code, which can be significant in this world of massive bundles.
And pack a bunch of assets into one larger asset, reduce the HTTP request count and maybe pre-gzip to save a few clock cycles
Maybe all of this should be an optional feature of HTTP servers and browsers with graceful fallback? NGINX could have a module that understands JavaScript and CSS and bundles and caches things on the fly, enabled optionally.

It would greatly simplify deployment to have the source and deployed code be identical. Obfuscation aside, given JS is an interpreted language, there is no reason to not use it for what it is. We've turned deploying JS into the same level of complexity as deploying C++ by adding building and packaging steps. Interpreted languages should never need build steps, and deployment should be no more than a simple rsync.

I thought I read in the Rails docs somewhere that HTTP2 and import maps rescued us from bundling JS
Bundling and minimizing can very significantly reduce code size, by eliminating unused code.

This is beyond the stripping comments, whitespace, renaming all symbols to short identifiers, replacing idiomatic constructs with shorter equivalents, etc. that people expect minifiers to be doing.

Bundling with tree shaking can get rid of a lot of code that would otherwise need to be downloaded. This is especially the case when using only a subset of functionality from a larger library.

Otherwise, for most libraries, if you pull in a single function, every single module from that library will also get loaded. This applies both the pre-bundled libraries (i.e. where there is only one large module, so obviously everything gets downloaded), and non-bundled libraries, because most libraries have you import from an "index.(m)js" module, that exports all the various public API of the library. Which means a browser with import maps will need to download all those files, and all files they import, which will be basically every module in the library.

Minimizers themselves often also have some sophisticated dead code elimination. Indeed, one potential (but inefficient) way to implement tree shaking is simply to bundler without shaking, while using module concatenation, and then simply passing it to a minifier with good dead code elimination capabilities. This would be able to eliminate basically anything tree shaking could, and more. The more comes from both from any eliminable code the bundler would not know how to eliminate, but also being able to eliminate anything that was only imported by said dead code.

This is one of reasons why uncompressed minified code can sometimes beat out the compressed original code, and is still at least somewhat compressible itself. Of course I have not even touched on having fewer files to download (which still has meaningful overhead), nor the smaller resulting codebase being faster to parse than the.

Lastly, but not least, many people want to use typescript or jsx when writing their code, which means the code needs to be pre-processed before a JavaScript engine will read it. If you already have a compile step, then adding bundling and minimizing on top of that can be relatively simple and make good sense for the above reasons. (Note can be simple. It depends a lot on what tools you use. Webpack for example can get really complicated, but it also offers some really powerful features.)

All your points are good, thanks, especially about the unused functions.

> many people want to use typescript or jsx when writing their code

However, if this is true, why don't we just add these languages to browsers (<script type="text/jsx">, <script type="text/typescript">) with some kind of client-side processor for old browsers that turns them into "text/javascript" in-line in the DOM if the browser doesn't support it?

It's kind of weird that JavaScript is becoming a common "bytecode" among other better-structured languages, one would think the bytecode language that becomes the compilation target should be one that is better designed of its own.

If we're compiling JS, JSX, and TS all to some sort of assembly, or even a statically and strongly typed language like C++, I would feel a bit better.

We touch on this in the docs [0]. TLDR, bundlers are still necessary (for now) to reduce the number of roundtrip requests required before page load (ideally to 1), and in more complex apps to avoid overwhelming the browser with parallel requests. Even HTTP2 can't handle 100k parallel requests for a big app with a bloated node_modules.

[0] https://bun.sh/docs/cli/build#why-bundle