Angular: Dynamic Importing Large Libraries

import() with Angular CLI

Suguru Inatomi
lacolaco-blog
4 min readMar 6, 2019

--

This post explains how to import large 3rd-party libraries into your Angular application without pain on initial payload size.

Example: Chart.js in Angular

Chart.js is a popular library to render rich charts. It contains a lot of features and its payload size is huge.

To use it in your Angular application, typically you write a import statement in TypeScript code and call it like the below;

As you can expect easily, this import makes main.bundle.js large. Increasing the initial payload size is one of what we want most to avoid.

Build result
Chart.js: ~500KB

Use import()

import() is a new feature of ECMAScript. It loads a script dynamically in runtime. In the future, all modern browsers support it natively. But today, its support is not enough.

Can I use… JavaScript modules: dynamic import()

No problem, webpack helps us. webpack can replaceimport() calls with its own dynamic module loading function in the bundling flow. You can imagine it just like a polyfill.

webpack: Dynamic Imports

Because Angular CLI uses webpack, we can use it, even in Angular CLI-based applications. There is no “eject”. Don’t worry! :)

Preparation: Edit tsconfig.json

Also, TypeScript has support for dynamicimport() , but it is enabled only in some module types. Open tsconfig.json at the root directory and set its module field to esnext . It doesn’t affect the final bundle’s browser compatibility because all module resolutions are solved by webpack behind of Angular CLI.

Migrate to dynamic import()

Call import() in the TypeScript code simply like following. That’s all…

normalizeCommonJSImport is a utility function for compatibility between CommonJS module and ES modules and for strict-typing.

For details about module compatibility, please read this.

In this case, TypeScript’s import() returns Promise<typeof Chart> as well as import * as Chart from ‘chart.js’. This is a problem because chart.js is a CommonJS module. Without any helpers,default doesn’t exist in the result of import() . So we have to mark it as any temporary and remark default as the original type. This is a small hack for correct typing.

As the result, you can see separated bundles like below. chart.<hash>.js is not marked as [initial]; it means this bundle is loaded lazily and doesn’t affect initial bootstrapping.

Build result
Dynamic loading in the browser

Conclusion

  • Static importing large libraries brings big pain for initial bootstrapping performance.
  • Dynamic importing will come to modern browsers in the future, and we can use it today with webpack’s help.
  • There are some issues which we have to care about around CommonJS-ESModules compatibility.

The full code example is here. Thanks.

--

--

Suguru Inatomi
lacolaco-blog

a.k.a. lacolaco / Google Developers Expert for Angular / ng-japan organizer