I have migrated my demo application to use the Closure compiler for bundling. In this post I will do a quick comparison of bundle sizes between Closure, Rollup and Webpack.

Closure is now very close to becoming a viable option for Angular application bundling. It still requires a few manual tweaks to RxJs, but things are starting to look really good.

I started working on a demo application back in May of 2015. Since then I've added more and more components to my repo.

The demo is now a fairly comprehensive application where I use most of the common Angular features including routing, http, forms, rxjs, etc.

Since the application exercises a large potion of Angular it seems like it makes for a good test candidate for Closure bundling.


RxJs is currently the last hurdle before we can call Closure compiler ready for “primetime”. I had to add a few hacks to the RxJs distro to make this work.

I am currently using the default commonJS build of RxJs. The rest of my app uses ES6, but Closure allows us to combine both formats in the same app through the --process_common_js_modules flag.

The –process_common_js_modules flag doesn't seem to work correctly in the current version of Closure, so I had to build a custom version from source. If you don't want to build it yourself you have to wait for the next release. Alternatively you can do an ES6 build of RxJs to avoid working with commonJS.

In either case, one of the challenges with RxJs is imports without an exported symbol.

These imports involve RxJs modules in the add/operator and add/observable folders. Modules in these folders have side effects since they all mutate the prototype of the Observable object.

For some reason Closure does not allow imports of modules without some exported symbol. This is most likely a bug in Closure.

To get around this I had to add an extraneous export to all imported operators/observables. This is a hack, but hopefully a temporary workaround.

Here is an example of this:

"use strict"; var Observable_1 = require('../../Observable'); var do_1 = require('../../operator/do'); Observable_1.Observable.prototype.do = do_1._do; Observable_1.Observable.prototype._do = do_1._do; // I added this as a workaround to make this work with Closure exports.__CLOSURE_WORKAROUND__ = true; //# sourceMappingURL=do.js.map

I had to add the same hack to all imported operators/observables.

Next let's look at the bundle sizes:

Webpack: 160k
Rollup: 151k
Closure Compiler: 107k

As you can tell, Webpack and Rollup are pretty close, but Closure is in a league of its own.

107k is a huge improvement!

I have pushed the code to Github if you want to check it out.

I have also deployed out demos of the three different builds.

You can find them here:

I also have an article where I compare some of the runtime metrics here.