Check out myAngular article series with live demos and Facebook group Angular - Advanced Topics

Angular Build with Webpack and Babili

Torgeir "Tor" Helgevold
- JavaScript Developer and Blogger
Published: Fri Jun 02 2017

In the following post I will show that you can shrink the footprint of your Angular Webpack build by switching to ES6 and Babili.

Angular currently ships in two different formats; flat ES5 and ES6 bundles.

I should point out that the ES5 build is not really a pure ES5 build since the bundle includes ES6 import and export statements. The reason for creating a hybrid format like this is better support for Tree shaking.

Why ship both ES5 and ES6?

The safest choice is still ES5 since it will run in all browsers without down leveling. However, there are some advantages to the ES6 build if you are targeting modern browsers.

Since Angular is written in TypeScript, the ES5/ES6 versions are down leveled versions of the original TypeScript. When transpiling TypeScript classes to ES5 you end up with relatively verbose representations of the original classes.

Let's look at a simple example from the Angular TypeScript source.

export class KeyRegistry { private _allKeys = new Map<Object, ReflectiveKey>(); get(token: Object): ReflectiveKey { if (token instanceof ReflectiveKey) return token; if (this._allKeys.has(token)) { return this._allKeys.get(token) !; } const newKey = new ReflectiveKey(token, ReflectiveKey.numberOfKeys); this._allKeys.set(token, newKey); return newKey; } get numberOfKeys(): number { return this._allKeys.size; } }

Below you can find the transpiled ES5 and ES6 versions of the original TypeScript.

ES5

var KeyRegistry = (function () { function KeyRegistry() { this._allKeys = new Map(); } KeyRegistry.prototype.get = function (token) { if (token instanceof ReflectiveKey) return token; if (this._allKeys.has(token)) { return ((this._allKeys.get(token))); } var newKey = new ReflectiveKey(token, ReflectiveKey.numberOfKeys); this._allKeys.set(token, newKey); return newKey; }; Object.defineProperty(KeyRegistry.prototype, "numberOfKeys", { get: function () { return this._allKeys.size; }, enumerable: true, configurable: true }); return KeyRegistry; }());

ES6

class KeyRegistry { constructor() { this._allKeys = new Map(); } get(token) { if (token instanceof ReflectiveKey) return token; if (this._allKeys.has(token)) { return ((this._allKeys.get(token))); } const newKey = new ReflectiveKey(token, ReflectiveKey.numberOfKeys); this._allKeys.set(token, newKey); return newKey; } get numberOfKeys() { return this._allKeys.size; } }

As you can see, the ES6 version is more compact. Obviously this difference in size will add up in large code bases like Angular.

Let's see how much I can shrink the build in Webpack by switching to ES6.

As a reference I have an existing ES5 Webpack build here.

In order to support ES6 in Webpack I have switched out Uglify for Babili since Uglify can't work with ES6 by default.

I have included the webpack config below:

const BabiliPlugin = require("babili-webpack-plugin"); module.exports = { entry: './built-es6/app/main.js', output: { filename: 'dist/bundle-webpack-babili.js' }, plugins: [ new BabiliPlugin({}, {comments: false}) ] }

Angular has introduced a new setting in package.json to reference ES6 bundles. This new setting is simply called “ES2015”. From what I can tell, this setting is not directly supported by Webpack.

To get around this I had to cheat by updating the established “module” setting in package.json to point to the ES6 builds. This will cause Webpack to pick up the ES6 bundles instead of the default ES5 bundles.

I have deployed the ES6 version of the app here.

As you can tell, the bundle size went from 151k to 143k.

The source code for this is available on Github.

If you liked this article, share it with your friends on social media:

We also have a new Facebook group about advanced Angular topics.

I invite you to follow me on twitter