/ angular

Faster Angular builds with HappyPack

In my recent post Angular CLI vs. Custom Webpack Setup I said that in my experience, build performance was one of the reasons not to use the CLI, and then I briefly mentioned HappyPack as a way to improve it. In this post I would like to give more details on this. I will show how to configure HappyPack and then will provide a comparison of build times with and without HappyPack, as well as compare those with Angular CLI's.

Configure HappyPack

First thing to mention is that you need to use ts-loader as the loader for TypeScript files in order to be able to use HappyPack. As far as I know, neither @ngtools/webpack nor awesome-typescript-loader support running TypeScript compilation in parallel with HappyPack.

ts-loader already has a good guidance on how to configure it together with HappyPack, I'll just summarize it here:

  1. Make sure you have installed ts-loader, fork-ts-checker-webpack-plugin and happypack packages with yarn or npm.
  2. Change the loader for ts files to happypack.
    rules: [
      ...
      {
        test: /\.ts$/,
        use: 'happypack/loader?id=ts'
      }
      ...
    ]
    
  3. Add the HappyPack plugin.
    const HappyPack = require('happypack');
    ...
    plugins: [
        ...
        new HappyPack({
         id: 'ts',
         threads: os.cpus().length - 1 /* at least 1 cpu for the fork-ts-checker-webpack-plugin */,
         loaders: [
           /* Add your additional TS loaders, like angular2-template-loader, angular-router-loader, etc.  */
           ...
           {
             path: 'ts-loader',
             query: {
               configFile: 'tsconfig.json',
               happyPackMode: true
             }
           }
         ]
       }),
       ...
    ]   
    
  4. Add ForkTsCheckerWebpackPlugin plugin.
    const HappyPack = require('happypack');
    const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
    ...
    plugins: [
        ...
        new HappyPack({...}),
        
        new ForkTsCheckerWebpackPlugin({
           checkSyntacticErrors: true,
           watch: ['./src']
        }),
    ]   
    

Build Times Comparison

To test the performance of the build I have generated a relatively large app (which you can find on GitHub). This app consists of 100 Angular modules and 1000 components.

Here are the measurements:

Development BuildProduction Build
Without HappyPack74 sec.360 sec.
With HappyPack17 sec. (4.2x faster)107 sec. (3.3x faster)

As you can see, the speed boost with HappyPack is huge. However, to be fair, the biggest speed improvement here is not because of HappyPack itself, but rather the combination of the happyPackMode option of ts-loader (which enables transpileOnly mode) and fork-ts-checker-webpack-plugin.

Angular CLI

I also tested Angular CLI with the same app. I tested with two versions of the CLI: 1.4.9 and 1.5.4 (because not everybody have upgraded yet and I thought it would be interesting to see the difference in performance between the two versions anyway). Here are the numbers:

Development BuildProduction Build
Angular CLI 1.4.9 (Angular 4)44 sec. (+27*)81 sec. (-26)
Angular CLI 1.5.4 (Angular 5)38 sec. (+21)282 sec. (+175)

* Difference compared to the builds with HappyPack.

What is surprising here is that the Production build is much slower with Angular CLI 1.5. This is partially because there more build optimizations going on for production builds with the latest version of the CLI, but the main cause looks to be an issue with ModuleConcatenationPlugin.

As an experiment, I commented out the ModuleConcatenationPlugin in node_modules/@angular/cli/models/webpack-configs/production.js and then ran the build again:

Development BuildProduction Build
Angular CLI 1.5.4 (without ModuleConcatenationPlugin)38 sec. (+21)94 sec. (-13)

This looks much better. Of course hacking Angular CLI like this is not an option for a real project and unfortunately there is no way to disable ModuleConcatenationPlugin in Angular CLI. Hopefully a new version with the fix will be released soon.

Conclusion

As you can see from the numbers above, HappyPack can quite significantly boost the speed of your build if you don't use Angular CLI and have a custom Webpack config with ts-loader as your TypeScript loader (or, if you use awesome-typescript-loader, you can easily switch to ts-loader).

However, if you use Angular CLI or a custom Webpack setup with @ngtools/webpack as your TypeScript loader, then difference in performance is not that big and production builds are even faster with the CLI (assuming the ModuleConcatenationPlugin issue is fixed). This is not surprising as the Angular CLI team did a great job making AOT compilation as efficient as possible as part of their @ngtools/webpack/AngularCompilerPlugin Webpack infrastructure, and it will probably continue to improve.

That's it, I hope information in this post gives you a good overview of how to configure HappyPack with ts-loader and what kind build speed improvements you can expect with it.



PS: Here are the links to the exact versions of the above GitHub repo that I used for taking those measurements above:

Pavlo Glazkov

Pavlo Glazkov

Programmer. Full stack, with a focus on UI. JavaScript/TypeScript, Angular, Node.js, .NET

Read More