Lazy Loading of NPM Packages Using Dynamic Import

Elad Elram
4 min readAug 30, 2021
Photo by Big Dodzy on Unsplash

Has this ever happened to you? You heard about this new feature, something you really want to try, and you look for a way to use it in your code. You then run to your TL and colleagues to try and convince them that “we must use it now!”. No? just me? 🧐

I have to admit that I had this kind of crash on dynamic import. It’s pretty easy to use, but I didn’t find a place to use it in a way that will make a difference - and then they asked me to add an “export to PDF” feature! 🤩🤑🥳

What is dynamic import?

Dynamic import is a pure JavaScript statement to import a module from another js file. Unlike static import, used in the head of the file, dynamic import can be used as a function inside your code block. When using the import as a function, it gets a path to the module file and returns a Promise that resolves with the module you asked for.

Static vs. Dynamic import

Since the import is a pure JS statement, you can use it in every JS-based app or framework like Angular, React, Vue, and Vanilla JS apps.

When should I use dynamic import?

Let’s take, for example, the export to PDF feature. If you consider exporting to PDF in your front-end app, you probably find yourself using the jsPDF library. jsPDF is great and getting the job done, but it’s pretty heavy; you will add about 348 kB to your bundle size.

More than that, chances are that only a small part of users will click on this export to PDF button but, if you are using static import, all of your users will get this package code in the bundle. This is outrageous; the bigger the bundle size — the slower the app’s initial load to all users, and only a few will use this code.

In the example below, you can see a simple React app compiled to production. The size of the initial js files has grown from 133kb to 479kb while we add a static import to jsPDF using import { jsPDF } from "jspdf";.

The size of a simple React app with static import to jsPDF

So what can we Do? Dynamic import to the rescue! 💪 We will import jsPDF lazily and only when we need it — after the user clicked on the button. Our initial bundle will remain untouched, and we will load the package only to users who need it. In the Gif below, you can see the chunk with jsPDF code loaded only after the click.

Dynamic import of jsPDF

Dynamic import & tree shaking

Photo by Kurt Cotoaga on Unsplash

One of the biggest disadvantages of using dynamic import is tree-shaking.

Tree shaking is a feature of bundlers (like Webpack and Rollup) that removes not-reachable code parts during the build to decrease the bundle size. If you use dynamic import, your bundler won’t do tree-shaking to this package because the logic relies on static import. This is the reason you find MDN advice to use dynamic import only on specific cases.

Well, 3 small comments about that:

  1. Unfortunately, not all packages are built with modularity that supports tree-shaking. So before you decide to skip dynamic import entirely, you should check it specifically on the package you need.
  2. Even if the package supports tree-shaking, you should look at the tradeoff. It’s may be OK for you to load the package lazily even if you get more code.
  3. It looks like the equation “dynamic import = no tree-shaking” is no longer applied in Webpack 5. You can check out this article.

Is dynamic import fits my need?

To sum up, here are a few questions you can ask yourself before deciding to import statically or dynamically.

  • What is the effect of the package on the bundle size?
  • How many times will a user use this package in the app?
  • What is better in terms of UX? To load the package in the initial bundle or lazily on demand?
  • Is the package support tree-shaking?

I hope the answers will help you make some educated decisions instead of automatically using the static import.

--

--