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' }
]
}
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' });
[...]
})
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:
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");
});
})
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' });
[...]
})
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:
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)