# Differential loading

Browser support considerations have been an ever growing concern of web developers, with new technologies increasingly leaving behind older "*legacy*" browsers, leaving them unable to handle the advanced syntax used in development today.

However, some of these legacy browsers still have their userbase, who understandably expect websites to work for them just as for those who use modern and frequently upgraded, so called "*evergreen*" browsers.

In the end, it falls on the developer's shoulder to provide the best experience for every kind of user, and in the case of legacy users, this is done by compiling the code to an older syntax comprehensible to their browsers (compiling ES6 down to ES5 is a typical example in *JavaScript*), and adding [polyfills](https://angular.io/guide/browser-support#polyfills) to the code that serve a similar purpose.

## The catch
However, this solution by default means that our compiled bundles will be burdened by the extra size of the *polyfills*, as well as extra compiling time, not to mention the lower performance of the older code syntax. This can even stack up to a 20% increase in initial load times, which is certainly noticeable, not to mention unnecessary for the vast majority of the users. 

It is not exactly fair that they should compromising their user experience for *legacy* browsers that they do not actually use, but dropping the *legacy* support would be unfair to others. Now, if only there was a way to combine the best of both worlds...

## A different(ial) solution

Enter the method of *differential loading*: at build, our compiler will check our loading configuration (```browserlists```, more on that later), cross reference it with our compilation *target* and if necessary creates two separate versions of our app, one intended for *evergreen* browsers and one for *legacy* ones. Later, the API checks the type and version of our user's browser, and decide which bundle to send out.

This means that newer browsers can skip the extra data and perform better without barring legacy users from the full functionality of our application.
Since all of this is happening automatically, the developer is also freed from many of the earlier considerations regarding [browser compatibility](https://angular.io/guide/browser-support).

It has to be mentioned that building two bundles will increase both building and deployment times, so it is up to the developer whether that is an acceptable trade-off for faster loading times on the user's side.

## How do separate bundles work

A new feature ```type = "module"``` lets our app differentiate between bundles intended for different browsers, since only later browsers understand this type definition, meanwhile older ones will fall back to to the ```nomodule``` script:

![bundles.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1650128749510/pDRu_aAv9.png)

However, because of the many different types and versions of browsers out there, adding the correct tags manually would be extremely time consuming. Luckily, a configuration tool called ```browserlists``` can help us out: in there we can define the range of browsers we intend to support, which will be used to generate the new bundles if needed. 

```browserslist``` can be configured either as an entry in ```package.json```: 

![package-browserslist](https://cdn.hashnode.com/res/hashnode/image/upload/v1650128611640/8SlCjhObE.png)

or as a separate ```.browserslistrc``` file:

![browserslistrc-file](https://cdn.hashnode.com/res/hashnode/image/upload/v1650128429793/XlcJAnuL7.png)

There are many different conditions we can use, with the full list accessible [here](https://github.com/browserslist/browserslist#full-list)

## Where is Angular in all of this?

Luckily, you might not have to deal with manually setting up *differential loading*.
In the case of Angular 8 or above differential loading is already integrated in the CLI, saving you the effort of configuring it to the compilers. 

Note: Angular 7.3 already used ```es5BrowserSupport```, but that could only handle *polyfills*, and is now deprecated.

Any new Angular project will include the ```browserslist``` file with the default settings, working as it should: right out of the box.

We can of course always tweak our ```browserslist``` configuration as we please, or completely switch the [feature off](https://betterprogramming.pub/how-to-reduce-angular-deployment-times-by-disabling-differential-loading-9215e2702bfb) (by enabling all, even dead browsers). Setting our compiler target to ES5 is also an option, which will mean our *differential loading* setup will only take care of optional *polyfills*.

Overall, it is recommended to take advantage of the feature as it can result in a 7-20% loading speed improvement, especially in larger apps.

Hope you enjoyed the brief introduction, and feel free to check out the [official Angular documentation](https://angular.io/guide/deployment#differential-loading) or the [Angular V8 documentation](https://v8.angular.io/guide/deployment#differential-loading?) for a deeper dive.

