In my earlier post, I covered about lazy loading of angular modules. In this post, I will cover lazy loading of scripts and styles, both external and local. The goal of this post is to show how you can defer loading of a script or style and load it manually later when you need.
This also works perfectly with external scripts that if added to the index.html file of your project would have a negative impact on performance. It works well with styles and scripts that are needed for a specific case. One such scenario that spring to mind is handling payment using PayPal.
In most cases, payment is usually processed only after a customer has order an item not before. In this case, loading PayPal by placing the script tags at the index.html would negatively impact performance while it’s only needed at the last step for payment processing.
Loading Scripts and Styles on Demand
You will most like be loading the scripts in a component. To load the style or script, we are going to use document.CreateElement
method to add a new script/style element.
For the script, we will create new scripts tags with the source pointing to our script URL. For the style, we will create new link element in the header, with HREF to our style URL.
To load our script, we begin by creating a new method loadExternalScript(scriptURL), which will return a promise. A promise will make it easier to ensure that we will use our script after it has been loaded successfully and not before.
return new Promise(resolve => {
const scriptElement = document.createElement('script');
scriptElement.src = scriptUrl;
scriptElement.onload = resolve;
document.body.appendChild(scriptElement);
});
The same goes for our style, where we will create a new method and then return a promise:
private loadExternalStyles(styleUrl: string) {
return new Promise((resolve, reject) => {
const styleElement = document.createElement('link');
styleElement.href = styleUrl;
styleElement.onload = resolve;
document.head.appendChild(styleElement);
});
}
You can wrap the above two methods in a class or service if you wish. It will make it easier to reuse the methods all over your class easily. Then, call the methods to load the scripts/style as show below:
this.loadExternalScript('url/to/your/scripts').then(() => {}).catch(() => {});
this.loadExternalStyles('url/to/your/styles).then(() => {}).catch(() => {});
And that’s it. You can now load styles/scripts on demand and not before. In the next step, I am going to cover how to lazy load local scripts.
Lazy Loading Local/Internal Scripts and Styles
When Angular CLI is building your application, all the styles and scripts added to the angular.json file are automatically added to the index.html, meaning they will be preloaded before rendering.
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"styles": [
"src/styles.css"
],
"scripts": [
"src/some-script.js"
],
//...
To avoid this, you can specify that a specific script/style is to be lazy loaded and angular will just output a bundle and won’t add it to the index.html. You do this by specifying the script/style in object format, instead of a simple string as shown above. The object formats allows you to provide more information to the CLI about how to handle a specific style sheet or script. This information includes the output name, whether to lazy load and the source of the style/script.
{
"input":"path/to/your/lazy-script.js",
"lazy": true,
"bundleName": "lazy-loaded-script"
},
You also must specify the output name (bundleName) to be able to reference to it later. If you don’t, Angular CLI will randomly generate a bundle name, which will change on each build.
"scripts": [
"src/some-script.js",
{
"input": "path/to/your/lazy-script.js",
"lazy": true,
"bundleName": "lazy-loaded-script"
},
],
"styles":
[
"src/some-styles.css",
{
"input": "path/to/your/lazy-style.css",
"lazy": true,
"bundleName": "lazy-loaded-style"
},
],