DEV Community

Victor De Grandis
Victor De Grandis

Posted on

How to do dynamic imports on AngularJs

Supose you have an AngularJs app and you use a lot of different libs for different features in your project. You don't have to load all the code at once in the first paint of the page, and download it even if is not used.
Here i pretend to present how to delay the loading of libs until is really needed, or not download them at if is not.
In my project im working with AngularJs, but with typescript, so im using babel-loader and ts-loader inside my webpack setup.

Tools

I used the webpack plugin babel-plugin-syntax-dynamic-import, that allow webpack to separate the code when we write an import() in our source and put it on a different bundle.

Setting typescript

Typescript with a default configuration (targeting es2015) doesn't allow to have imports() beneath the code, it wants them on the first lines of the file, so we have to set "module": "esnext" on our tsconfig.json so typescript can undestand imports

Configure Webpack

Our webpack config must declare the syntax-dynamic-import beside the babel-loader:

{
    test: /\.ts?$/,
    use: [
        {
            loader: 'babel-loader?cacheDirectory',
            options: {
                plugins: ["syntax-dynamic-import"]
            }
        },
        { loader: 'ts-loader' }
    ]
}
Enter fullscreen mode Exit fullscreen mode

This allows the babel-loader to interprate the import() on the middle of our code, and what Webpack does when reachs one import statement is creates a new bundle with the library you are trying to import, so the lib code is not loaded in other bundles, only on this separate one.

Using imports in your code

Now its all ready to put use the lib we need in our code:

import("XLSX").then((XLSX) => {
  var ws = XLSX.utils.json_to_sheet(data, { header: colHeaders, dateNF: 'dd/MM/yyyy hh:mm' });
  [...]
})
Enter fullscreen mode Exit fullscreen mode

Here im using the import as a promise so its downloaded first, and then run the code where i needed it (it can be treated as a async/await too)
In the import i declare that i need the "XLSX" lib (which lets you export a grid to a .xslx file), and then i used it as always inside my .then() statement.
And using the app we see how chrome download the bundle only when the code is reached:

Alt Text

If i need another library at the same moment, i can chain promises (or asyncs if i wish):

import("XLSX").then((XLSX) => {
  var ws = XLSX.utils.json_to_sheet(data, { header: colHeaders, dateNF: 'dd/MM/yyyy hh:mm' });
  [...]
  import("../../node_modules/file-saver/FileSaver.min.js").then((fileSaver) => {
      fileSaver.saveAs(new Blob([s2ab(wbout)], { type: "application/octet-stream" }), options.exportarExcel + ".xlsx");
    });
})
Enter fullscreen mode Exit fullscreen mode

In this example i'm using FileSaver to save the actual file im generating with XLSX, its a lib i don't need anywhere else, so i only downloade it in my code in this exact moment, and free the rest of my app from its weight.
I can reference XLSX as XLSX in the import statement because is declared as an alias in my webpack, if you dont have it you can use the url as in the FileSaver example.

Naming chunks

Thats good enough, but sometimes life is not as easy and you need to put more cod inside the same chunk, or you need to use the lib sometimes as static and sometimes dynamically, so for that is very useful to name the dynamic bundle:

import(/* webpackChunkName : "xlsx" */ "XLSX").then((XLSX) => {
  var ws = XLSX.utils.json_to_sheet(data, { header: colHeaders, dateNF: 'dd/MM/yyyy hh:mm' });
  [...]
})
Enter fullscreen mode Exit fullscreen mode

This way webpack will generate a separated bundle when reaches this code, but it won't be a unnamed javascript, but named xlsx.js, so if you need it anywhere else you can reference it:

Alt Text

Conclusion

The first paints of every application are the most important ones in loading and performance, so every byte we can save worth our time.
But with so many cool features our applications can have now with the greate amount of libs out there, we don't want neither leave features aside because of their weight nor punish the first paint for it, and we don't need to if we use the right tools to manage correctly the loading.

Top comments (0)