
Closure Compiler vs Rollup vs Webpack - thelgevold
http://www.syntaxsuccess.com/viewarticle/closure-compiler-vs-rollup-vs-webpack
======
michaelbull
This seems misleading. Rollup doesn't ship with an uglifier/minifier, and
Webpack ships with UglifyJS. So what you're really comparing is UglifyJS vsthe
Closure Compiler, however both webpack _and_ rollup have plugins for utilizing
the closure compiler:

[https://github.com/roman01la/webpack-closure-
compiler](https://github.com/roman01la/webpack-closure-compiler)

[https://github.com/camelaissani/rollup-plugin-closure-
compil...](https://github.com/camelaissani/rollup-plugin-closure-compiler-js)

------
susi22
I remember back in the day, Google Closure was so advanced they even tried out
shuffling code around in the final JS file and measured which way produced the
best GZIP compression. They since abandoned that code though, but that's
something they did over 5 years ago.

~~~
cromwellian
You can see some of the original research I did on this in my old blog post:
[http://timepedia.blogspot.com/2009/08/on-reducing-size-of-
co...](http://timepedia.blogspot.com/2009/08/on-reducing-size-of-
compressed.html) I followed up by researching different clustering metrics
including something called LZDIST instead of edit-distance.
[http://timepedia.blogspot.com/2009/11/traveling-salesman-
pro...](http://timepedia.blogspot.com/2009/11/traveling-salesman-problem-
and.html)

I think it works better for GWT than for Closure because GWT's optimizer
permits inlining functions in some circumstances even if they increase code
size. This causes repetitious fragments to appear, and re-ordering the code to
bring those fragments within GZIP's compression window functions as kind of a
late-stage "anti-inliner/common subexpression elimination"

------
noway421
Last time playing with closure, it did quite a good job of dead code
elimination.

Is there a specific reason why simple code elimination is not as wide spread
as tree shaking, although it seems to be simpler and more effective solution?

------
pabl0rg
Closure probably fell out of vogue because it's excellent, but written in
java.

~~~
michaelbull
There's a JavaScript version available that has feature parity with the Java
version.

[https://github.com/google/closure-compiler-
js](https://github.com/google/closure-compiler-js)

~~~
merb
that's only a transpiled version of it:

    
    
        The Javascript version of the Closure-Compiler is
        transpiled by GWT from the Java source. For more details
        on the differences in behavior see the super sourced
        files in the main repo.

~~~
fnordsensei
Is that an issue?

~~~
lgas
No.

~~~
merb
(But it's slower ;))

~~~
cestith
Is _that_ an issue? ;-)

------
wildpeaks
You can also use Closure Compiler (instead of UglifyJS) with Webpack:
[https://github.com/roman01la/webpack-closure-
compiler](https://github.com/roman01la/webpack-closure-compiler)

~~~
abritinthebay
Caveat: it's really, really, _really_ , slow if you use the JS implementation.
Still needs Java for perf reasons. They do mention that tho.

------
BinaryIdiot
That's pretty interesting. Do we have any comparisons on the performance of
the outputted code between each? Like do they all perform identically? Are
there optimizations one may do that others do not or perhaps even the opposite
like a shortcut that cuts down on code but makes it perform worse? Also what
about memory performance?

It's been a while since I've used closure. I may look into this to do a
comparison on my current open source project and see what difference, if any,
it makes.

------
Silhouette
Unfortunately, recent versions of Closure Compiler don't appear to produce
entirely reliable output when run with the advanced optimisations that make it
interesting and give the kinds of impressive results observed by the OP here.

Case in point: We just installed the latest version on a new computer
yesterday, and it causes some JS code that runs fine in its original form to
fail on IE11 after transformation. The original code isn't complicated at all
and multiple developers and lint tools think it's correct and not doing
anything non-standard, but the transformed version seems to confuse IE. In
fairness to Closure Compiler, we also can't immediately see why the
transformation it has applied would be invalid, so maybe this is really a bug
in IE's JS parser or something along those lines. Unfortunately, the fact
remains that the original code works, the slightly different transformed
version from a previous version of Closure Compiler also worked, but the
transformed code in the new version does not.

------
kybishop
What is closure compiler doing that makes it so much better (for this
benchmark) than webpack or rollup?

~~~
nilliams
Example from the docs [1], Closure compiler can combine 'aggressive renaming',
'dead code removal' and 'function inlining', so it can compile:

    
    
        function unusedFunction(note) {
          alert(note['text']);
        }
        function displayNoteTitle(note) {
          alert(note['title']);
        }
        var flowerNote = {};
        flowerNote['title'] = "Flowers";
        displayNoteTitle(flowerNote);
    

to:

    
    
        var a={};a.title="Flowers";alert(a.title);
    

For comparison, rollup created:

    
    
        function displayNoteTitle(note) {
          alert(note['title']);
        }
        var flowerNote = {};
        flowerNote['title'] = "Flowers";
        displayNoteTitle(flowerNote);
    

... (which you'd then have to minify, but as you can see it only eliminated
the unused function).

[1] [https://developers.google.com/closure/compiler/docs/api-
tuto...](https://developers.google.com/closure/compiler/docs/api-tutorial3)

~~~
josteink
Intuitively I would assume that for most codebases dead-code removal would
have the biggest impact, especially when importing third-party libraries and
only using portions of them.

But from your comment I can see that rollup should be able to handle this too.
Yet the data in the linked article seems to imply Google Closure compiler
still can optimize the code 33% further.

I find it hard to imagine that inlining functions can make that kind of
difference.

Is it the test which contains flawed data? Or is this just an area where it's
hard to generalize results due to the varying characteristics of different
code-bases? Anyone got an opinion?

~~~
nilliams
I compared the output bundles (ran them back through a beautifier for sanity)
and it looks like a lot of the benefit comes from the aggressive renaming.

Compare this section of the rollup output:

    
    
        return e || (e = new zh({
            enableLongStackTrace: dt()
        })), e.run(function() {
            var r = yh.resolveAndCreate([{
                    provide: zh,
                    useValue: e
                }], n.injector),
                o = t.create(r),
                l = o.injector.get(th, null);
            if (!l) throw new Error("No ErrorHandler. Is platform module (BrowserModule) included?");
            return o.onDestroy(function() {
                return _t(n._modules, o)
            }), e.onError.subscribe({
                next: function(t) {
                    l.handleError(t)
                }
            }), bt(l, function() {
                return o.injector.get(bh).donePromise.then(function() {
                    return n._moduleDoBootstrap(o), o
                })
            })
        })
    

To this from Closure compiler:

    
    
        var c;
        c || (c = new Af({
            Lm: yh()
        }));
        return c.run(function() {
            var d = Ne([{
                    sb: Af,
                    Be: c
                }], a.s),
                e = b.create(d),
                f = e.s.get(ee, null);
            if (!f) throw Error("No ErrorHandler. Is platform module (BrowserModule) included?");
            e.ec(function() {
                return Hh(a.mi, e)
            });
            c.hq.subscribe({
                next: function(a) {
                    f.handleError(a)
                }
            });
            return Ch(f, function() {
                return e.s.get(Ze).xp.then(function() {
                    Eh(a, e);
                    return e
                })
            })
        })
    

On top of that I did a basic comparison of the number of times the 'function'
keyword is present in each bundle:

    
    
        $ ag --count function eg-closure.js
        eg-closure.js:2905
    
        $ ag --count function eg-rollup.js
        eg-rollup.js:4421
    

Whether this is from inlining or 'better' dead-code removal I can't really
tell.

~~~
jessaustin
_...a lot of the benefit comes from the aggressive renaming._

ISTM if we're going to compress the file anyway, renaming would have a much
smaller effect on what actually gets served?

