Now that the Closure compiler is closer to becoming a viable option in Angular, I have decided to start migrating my Angular demo components to use it. I will give you updates on my progress as I continue to work on the migration.
If you are new to the Closure compiler in Angular you might want to check out my other article about application bundles in Angular.
I have put the code on Github in case you are interested in checking it out.
The samples in this article rely on a custom snapshot build of Angular. The snapshot can be downloaded from npm using the following packages:
In the first phase I have focused on migrating components using the following modules: FormsModule, ReactiveFormsModule and the RouterModule.
I am using ReactiveForms to build a dynamic survey form. The details of the dynamic form is described in one of my previous articles.
Migrating the dynamic form to use the Closure compiler was painless. The original code worked as intended without any modification.
I am currently not using the FormsModule for forms functionality. I only use it to get access to NgModel and two way binding (banana in a box).
I added a simple demo demonstrating two way binding between a name property and an input box.
The NgModel sample worked as expected, without any issues.
I have added basic navigation to my demo page to allow users to route to my demo components.
The router worked out of the box without any modifications.
One of my demos is a data-bound, sortable grid, made to not make assumptions about the columns in the bound dataset.
Details about the grid can be found in one of my other articles.
The grid expects you to pass in “rows” and “column” objects. The “rows” object contains row data for the grid. The column object defines metadata for bound columns and defines which columns to show.
The grid will only display data for columns defined in the columns object. In the current code I am doing dynamic filtering by column name. This implementation uses dynamic property access using square brackets (e.g. row[column.name]).
One of the challenges with this metadata approach is that property mangling might cause the column object and the row object to fall out of sync.
As you may know, the Closure compiler will aggressively shorten (mangle) property names. This is usually fine, but here the compiler won't understand the relationship between the name in the column object, and the corresponding property in the row object.
As an example, shortening the firstName property in the row object will break the connection back to 'firstName' in the column object.
One solution to this is to define property names in the row object using quotes around the property names like so:
This works because anything in quotes will be left alone by the Closure compiler. After I added the quotes, the link back to the column definition is no longer broken.
Adding quotes worked, but it required a change to the original code. This may not be desirable in all cases, so hopefully there will be a better way eventually.
My understanding is that we will eventually be able to protect objects from mangling by specifying an interface with a “declare” statement.
I have tried this approach by adding a person interface to represent the row data, but have not been able to get it to work yet. Here is my interface for the items in the row object:
To evaluate the Closure compiler build of my demo app I have deployed it side by side with a regular Rollup build.
You can compare the bundle sizes here:
As you can tell the bundle size is definitely reduced when using the Closure compiler. The original Rollup size of 130k is reduced to a payload of only 79.2k. This is a decrease of 39%.
You can also take a look at the source-map-explorer view into the bundle here. As you can tell the Angular framework dependencies are pretty slim at this point. Worth noting that 31% of the bundle is now application code (20%) and rxjs (11%).