JavaScript bundles factorization while grouping shared dependencies

A very important part of the build phase of a single-page app it’s the bundling process, which consists in combining the app’s files and modules needed in order to run it.

In Mango’s Dashboard we used Browserify to structure the front-end.

Browserify provides lots of advantages and useful features as we outlined in this post.

The simplest bundling process using Browserify has an output of a single JavaScript file that contains the whole application logic.

The problem with single bundles

As new features are added to the app, the size of the bundle also increases and create some inconvenients:


– Download time increases.
– Time to interpret the code also increases.

Our Dashboard -like most single-page apps- needs to download, parse and interpret code before rendering the views.
This creates longer waiting periods before being able to use the app, directly affecting the user experience.

The first problem -although real- it does’t manifest in a linear fashion as the output code increases. As TJ VanToll points out, gzip compression is very powerful and works better with larger files (the bigger the file, the more repetitions it needs to find).

The bigger problem relies with the parsing and interpreting timeframe of the initial code.

Filament Group made an interesting analysis about the penalisation of using certain popular MVC frameworks that provides a clear vision of the problem.

factor-bundle to the rescue

factor-bundle works as a Browserify plugin that receives multiple files as entry points (in our case are mapped to the sections of our app), analyses their content and generates two things: an output file for each input file, and also an extra file that contains the related dependencies between them.

Thanks to this ‘factorization’ of dependencies, when users load the app, only downloads the JavaScript associated to the section that they’re visiting and the related dependencies. The remainder sections will only download in an asynchronic way and without repeating the dependencies downloaded while the users navigate the Dashboard.

A small optimization we make is for each output file creating another file with the shared dependencies. This avoids downloading an extra script (-common-.js).

The output after the process looks like this:

.
|-- config-0.3.6.js
|-- config-common-0.3.6.js
|-- login-0.3.6.js
|-- login-common-0.3.6.js
|-- store-single-0.3.6.js
|-- store-single-common-0.3.6.js
|-- stores-0.3.6.js
|-- stores-common-0.3.6.js
|-- user-0.3.6.js
`-- user-common-0.3.6.js

There are optimisations to delay downloading not used modules, i.e. detecting mouse proximity to links to different sections or similar strategies. We decided to talk about these optimisations in future posts.

Conclusions

Separating bundles resulted in an optimization of waiting times of around 30% when users logged in to our Dashboard; thanks to the decreased size of the initial script and also the fewer amount of code to interpret. Also, adding new sections doesn’t impact the performance of the app’s initial load.

There are a lot of techniques to enhance the initial load of single-page apps. One we’re investigating right now is the shared rendering between client and server. A very interesting advantage of bundle factorization is that it’s almost exclusively a change in the compilation process of the app.
Business logic and rules remained intact.

Any doubt, comment or experiences you want to share, please contact me via Twitter: @dzajdband.

Los comentarios están cerrados para este artículo.