Comparing the Closure compiler to Uglify
syntaxsuccess.com
syntaxsuccess.com
There's a larger list of restrictions at https://developers.google.com/closure/compiler/docs/limitati...
If you do write code obeying these rules (check out the closure library), or you use something like ClojureScript that generates straightforward, monomorphic, closure-compiler-compatible js, the payoff in both file size and parse/execution performance is pretty great.
The only downside is that it's slow. Like really slow. It takes about a minute to minify our app.
Edit: Looks like Uglify has gotten better lately. I'll submit a separate top-level comment.
It wraps the TypeScript Compiler and outputs CC compatible type annotation comments.
- It's a hack on top of TypeScript compiler
- It gets broken by TypeScript upgrades and is usually several weeks behind TS version upgrades.
I'd be really wary using it in production
- Pretty much everything you use (e.g. Angular or React or Babel or Webpack or equivalents in other languages) is being built by a handful of people
- It interacts with TypeScript in a way that tends to be more sensitive to changes, but being some weeks behind the latest release of a compiler is not the end of the world, and we do continuously upgrade
I agree you should be wary of using it in production though because it's not really user-friendly yet. Though if you can figure it out it does work and some people are successfully shipping some apps.
I can't justify bringing it in in our current setup though :(
Also, we seem to run into correctness bugs more often that we would like. I guess we are really stressing it.
- For developers creating websites. The cost of set-up would be high because you'd need concatenation+minification+etc in place, so I'd love seeing some examples to see whether or not is worth it. From what I know, this could be similar to tree-shaking, so there could be huge gains here.
- For library creators. However the top-most variables would have to be preserved, since other developers need to use them (which seems possible[1]), so I'll be trying it out.
I am also wondering about the performance boost for JS (besides file size) and whether this would be useful for something like Node.js or not (free performance). If anyone has more information please share it.
I don't have a direct comparison to Uglify, but as of last fall advanced optimizations does save us about 2.5 MB over simple optimizations.
We're also using Tsickle (https://github.com/angular/tsickle) and Clutz (https://github.com/angular/clutz) to be able to use TypeScript with our Closure Compiler compatible codebase. Closure Code can be depended upon in TypeScript code and vice versa. It's been awesome to use the type system of TypeScript in combination with the minification power of the Closure Compiler. The build process is definitely a bit crazy at the moment, though.
Disclaimer: I work at Lucid Software.
What these comments don't mention though:
- Angular's build system is an unholy mess, good luck understanding how it works
- They had to build their own tools such as hacks into TypeScript compiler to make sure Google Closure Compiler understands their code
Other "answers" reference things like "a custom snapshot build of Angular".
$ wc -c index.js | grep -v total
9320511 index.js
$ cat index.js | time closure-compiler \
--warning_level quiet \
--third_party \
--jscomp_off es3 \
--compilation_level SIMPLE_OPTIMIZATIONS \
--language_in ECMASCRIPT5 > index.js.closure 2>/dev/null
33.54s user 0.93s system 369% cpu 9.336 total
$ cat index.js | time closure-compiler \
--warning_level quiet \
--third_party \
--jscomp_off es3 \
--compilation_level ADVANCED_OPTIMIZATIONS \
--language_in ECMASCRIPT5 > index.js.closure-advanced 2>/dev/null
33.54s user 0.93s system 369% cpu 9.336 total
$ cat index.js | time node_modules/.bin/uglifyjs \
--screw-ie8 --mangle --compress - > index.js.uglify 2>/dev/null
18.88s user 0.24s system 103% cpu 18.475 total
$ wc -c index.js.*. | grep -v total
1750478 index.js.closure
1515331 index.js.closure-advanced
1763350 index.js.uglify
$ gzip -9 index.js.*
$ wc -c index.js*.gz | grep -v total
369749 index.js.closure-advanced.gz
397468 index.js.closure.gz
387896 index.js.uglify.gz
(Closure 20170218 on Oracle Java 8, uglify-js 2.4.19 on Node 6.8.1, running on MBP Pro 2015).It's worth noting that Closure is heavily parallelized, and uses 50% of the time to complete by using all 4 cores at almost 100%. If you only have one core, though, Closure will be much slower.
Our apps don't use any of Google's conventions, but Closure is still able to minify as well than Uglify. I don't know if there are any specific Closure or Uglify options that could make a bigger difference.
Also worth noting that we only minify for staging/production, not during development, which would incur too much of a performance hit.
We've always used Closure, and been very happy with it.
The result was about 20% savings ungzipped; 10% savings gzipped.
Granted, this is only possible if you reference modules/classes uniformly by the same name across your source, rather than using CommonJS "import as", and it only applies if you have no or few external dependencies which isn't realistic in the general case. Supposedly, using ES6 modules fixes this but I haven't checked yet.
Combining es6 and commonJS in the same project.
Edit: See this comment: https://news.ycombinator.com/item?id=13910621.
It did however save a few kilobytes - after gzip - but took around 3-4X longer to run (much worse if you use their JS implementation for Webpack)
If time to build is not an issue for you, and you're ok with the java dependency, then it might be worthwhile.
I'm sure in other specific cases it may be a lot better. Just not in mine.
That's probably just fine when you are transpiling (i.e. Google Web Toolkit) but its a PITA for everyone else.
It baffled me a bit that someone in comments on OP site abbreviated Closure Compiler as GCC. Imagine my surprise reading that GCC is written Java.
It's impossible to reliably set up Closure compiler if you are outside of Google's infrastructure and/or outside of Google's Closure Library.
End of comparison.
- The official docs are basically non-existent.
- If you're lucky enough to realize that GitHub wiki has better docs, good luck figuring them out.
- Even though the support for node_modules is kinda finally there, it's still impossible to figure out how to reliably set the compiler in a way that recognizes them.
My old-ish rant about this: https://gist.github.com/dmitriid/7bd6f2c10d263bae40e0addc7ed...
In my personal experience I couldn't get the compiler (none of the versions) work with a simple-enough project and node_modules in all the correct places.
UglifyJS just works.
Just pipe your JavaScript into Closure and it will minify it as easily as Uglify. We're migrating to Webpack, but we've been using this for about 4 years:
node_modules/.bin/browserify index.js | closure-compiler \
--warning_level quiet \
--third_party \
--jscomp_off es3 \
--compilation_level SIMPLE_OPTIMIZATIONS \
--language_in ECMASCRIPT5 \
--create_source_map "index.min.js.map" \
--output_wrapper "%output%//# sourceMappingURL=/index.min.js.map" \
> index.min.js
This generates a minified file plus a source map.Part of the magic happens in Browserify [1], which generates a single file from all your inputs, taking care to follow the import chains in the correct order. If you have ES6 code, you'll just install Babel and add "-r babel-register" to the Browserify command line.
I read the rant in your other comment, and I don't understand what it was that you struggled with. You certainly don't need to follow Google's Closure conventions in order for it to optimize and minify your code effectively. We don't; we use React and Babel with all the ES6 bells and whistles, but none of the Google conventions.
So maybe concatenating everything works with Closure Compiler. I don't know. We couldn't make it work with their advertised support for node_modules.