Written by Houssein Djirdeh

Reduce JavaScript payloads with code-splitting

Nobody likes waiting. Over 50% of users abandon a website if it takes longer than 3 seconds to load.

Sending large JavaScript payloads impacts the speed of your site significantly. Instead of shipping all the JavaScript to your user as soon as the first page of your application is loaded, code-split your bundle into multiple "pieces" and only send what's necessary at the very beginning.

Measure

Lighthouse displays a failed audit when a significant amount of time is taken to execute all the JavaScript on a page.

A failing Lighthouse audit showing scripts taking too long to execute.

Split the JS bundle to only send the code needed for the initial route when the user loads an application. This minimizes the amount of script that needs to be parsed and compiled, which results in faster page load times.

Popular module bundlers like webpack, Parcel, and Rollup allow you to split your bundles using dynamic imports. For example, consider the following code snippet that shows an example of a someFunction method that gets fired when a form is submitted.

import moduleA from "library";

form.addEventListener("submit", e => {
  e.preventDefault();
  someFunction();
});

const someFunction = () => {
  // uses moduleA
}

In here, someFunction uses a module imported from a particular library. If this module is not being used elsewhere, the code block can be modified to use a dynamic import to fetch it only when the form is submitted by the user.

form.addEventListener("submit", e => {
  e.preventDefault();
  import('library.moduleA')
    .then(module => module.default) // using the default export
    .then(someFunction())
    .catch(handleError());
});

const someFunction = () => {
    // uses moduleA
}

The code that makes up the module does not get included into the initial bundle and is now lazy loaded, or provided to the user only when it is needed after the form submission. To further improve page performance, preload critical chunks to prioritize and fetch them sooner.

Although the previous code snippet is a simple example, lazy loading third party dependencies is not a common pattern in larger applications. Usually, third party dependencies are split into a separate vendor bundle that can be cached since they don't update as often. You can read more about how the SplitChunksPlugin can help you do this.

Splitting on the route or component level when using a client-side framework is a simpler approach to lazy loading different parts of your application. Many popular frameworks that use webpack provide abstractions to make lazy loading easier than diving into the configurations yourself.


Codelabs

See it in action

Learn more and put this guide into action:

Reduce JavaScript payloads with code-splitting Start