Published on

Differential Loading for Legacy Browser Support in Angular 9

  • avatar
    jen chan

Two-headed monster from Sesame Street

This post discusses ways to support “legacy” browsers in terms of IE 11, and tuning Angular to support differential loading.

Before we changing build configs, there are 4 different scenarios you could end up with:

  1. 1 ES5 build (differential loading disabled, target is es5)
  2. 1 ES5 build with conditional polyfills (differential loading enabled, target is es5)
  3. 1 ES2015 build (differential loading disabled, target is es2015), which won't support IE 11
  4. 2 builds with conditional polyfills (differential loading enabled, target as es2015) This doc explains how to accomplish #4.


  1. Enable differential loading by making the tsconfig.json target: es2015 (Javascript ES6).

Little has changed from Angular 8 other than retiring of the es5BrowserSupport tag. Follow the steps below for adding with configurations targetting es5 export in your build and serve (on local dev) your app for legacy browsers.

  1. Ensure .browserslist includes all versions of browsers the project intends to support. This file refers to the compile configuration tool browserslist. Each statement in browserslist is read as a query string, which is runs against Can I Use data on support of various language features. Their github has great explanations of how to write accurate queries.

On build, Browserslist determines which browsers the app supports, and compiles JS files for ES5 (to support legacy browsers) and ES6+ supporting modern browsers.


Check for various es6 expressions and update polyfills.ts file with the necessary polyfills. It would be good to take stock of what kind of modern development features you're using. For example, IE 11 doesn't support flex grid, as well as ES6-ES11 features such as .includes(), promises, for-of or Object.keys() iteration, and optional chaining.

Angular’s “Browser Support” docs suggest classlist, all the core-js elements and web-animations if you are using Angular Material, but in the interest of keeping our legacy browsers' bundle size small, we should only polyfill for classlist and the ES6, ES7-11 features that our projects use. Make sure you npm install the polyfill package before you import it into polyfill.ts.

Diagram of differential loading

In tandem with the polyfills.ts, step tells Angular to export a bundle for modern browsers, and a bundle for legacy browsers.

How Do We Know It Worked?

After you run ng build --prod and check your dist/ or project folder, you’ll notice your index.html contains something like the following:

<script src="fancyModernBundle-es2015.js" type="module"></script>
<script src="legacyBundle-es5.js" nomodule></script>

Differential loading exports 2 sets of markup in Angular When you run the project locally or visit the deployed development version, open up the network tab of the developer tools and refresh the page. For modern browsers, you should see only the scripts that include -es2015 in the name. For IE 11, you would only see scripts that include -es5 in the name, and it will ignore any script tags with the type, module.

To compare bundle sizes, run this bash script gist by Jackub Rybinski

For more info about maintaining bundle size, check out: Suguru Inatomi, "Differential Loading" - A New Feature of Angular CLI v8, Apr 17, 2019

[Pro Tip] How to analyze your Angular bundle, Sep 13, 2019

💖🔥🦄 7 reactions on