Webpack Bundle Analyzer and Ionic

As a way to procrastinate on my latest mobile app, I started to look into reducing the size of the vendor file—that is, the external libraries that are bundled with my application code. In theory, a bigger application means slower startup times, which translates into a worse user experience. So just useful enough to be worthwhile but a great way to put off doing the actual development...

Like Kindertron Flash Cards, I'm developing it in JavaScript using Ionic. This uses Webpack (or optionally Rollup) under the hood, but abstracts the build system by default.

My first order of business was determining what exactly what in my vendor file. Webpack packs all the 3rd-party libraries together into a single file, so I needed a way to inspect it and see exactly what was included.

Webpack Bundle Analyzer

I found a plugin which does exactly this: Webpack Bundle Analyzer. It runs as part of the build and outputs a lovely treemap visualization.

Since Ionic hides the Webpack configuration by default, but it's surprisingly easy to get this integrated:

  1. Install the plugin

     npm install --save-dev webpack-bundle-analyzer
    
  2. Open the package.json and add this section:

     "config": {
       "ionic_webpack": "./config/webpack.config.js"
     }
    
  3. Create this file webpack.config.js:

     const webpackConfig = require('../node_modules/@ionic/app-scripts/config/webpack.config');
     const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
    
     webpackConfig.prod.plugins.push( new BundleAnalyzerPlugin({
         analyzerMode: 'static',
         generateStatsFile: true
     }))
    

    You can put it anywhere you like, just don't forget to update the paths in both package.json and the file.

  4. Do a production build:

     ionic build --prod
    

During the middle of the build, a new browser window will open with the results of the bundle analysis.

The above config only added it for production builds, so that's the only time it will appear. I don't think regular builds will give meaningful numbers, so this should be fine.

Reducing Vendor.js

Webpack supports tree shaking, and it works in Ionic as well. However, there may be code changes required for it to have the maximum effect. Many older libraries aren't modularized in a way that lets the tree shaking algorithm work. This is most evident in the large Lodash rectangle above. I'm not using all the features of Lodash, but the entire thing is being included. So it was my first step towards a smaller build.

First, I switched from Lodash to Lodash-es, which is a modularized build.

This didn't actually do anything to the vendor.js file, just swapped out one monolithic Lodash module for 631 modules. In order to tree shake correctly, I have to avoid importing the entire module at once. So I went through my entire code base replacing this:

import * as _ from 'lodash'; 

with this:

import cloneDeep from 'lodash-es/cloneDeep'; 
import omit from 'lodash-es/omit'; 
...

I never import anything directly from lodash-es; always from the sub-module. This reduces the build quite a bit:

At this point my Lodash usage went from 527KB to 155KB! That's a pretty hefty reduction in size.

I was so motivated, I continued onto Rxjs. I'm not going to go into detail, but basically I switched to pipeable operators which were recently shipped in version 5.5. This took me from 850KB to 558KB.

Next Steps

As I showed at the beginning, it's pretty easy to enable Webpack Bundle Analyzer without messing with Ionic's default build system. And once it's enabled, it's easy to see how it changes over time.

However, the biggest downfall to all this work was that my overall vendor.js went from 5.55MB to 4.9MB—a 12% reduction. The major culprits in my vendor file are Ionic-angular (1.4MB) and @angular (1.1MB) themselves. Firebase also takes up almost 1MB. So while it's great that I'm making improvements, the lower bound on vendor.js is still pretty large.