Skip to main content
web.dev
Resources
  • Web Platform
  • Dive into the web platform, at your pace.
  • HTML
  • CSS
  • JavaScript
  • User experience
  • Learn how to build better user experiences.
  • Performance
  • Accessibility
  • Identity
  • Learn
  • Get up to speed on web development.
  • Learn HTML
  • Learn CSS
  • Learn JavaScript
  • Learn Performance
  • Learn Accessibility
  • More courses
  • Additional resources
  • Explore content collections, patterns, and more.
  • AI and the web
  • Explore
  • PageSpeed Insights
  • Patterns
  • Podcasts & shows
  • Developer Newsletter
  • About web.dev
Baseline Blog Case Studies
/
  • English
  • Deutsch
  • Español – América Latina
  • Français
  • Indonesia
  • Italiano
  • Polski
  • Português – Brasil
  • Tiếng Việt
  • Türkçe
  • Русский
  • עברית
  • العربيّة
  • فارسی
  • हिंदी
  • বাংলা
  • ภาษาไทย
  • 中文 – 简体
  • 中文 – 繁體
  • 日本語
  • 한국어
Sign in
  • Resources
Privacy Accessibility HTML Images Responsive Design Forms PWA CSS Performance Testing JavaScript
web.dev
  • Resources
    • More
    • Privacy
    • Accessibility
    • HTML
    • Images
    • Responsive Design
    • Forms
    • PWA
    • CSS
    • Performance
    • Testing
    • JavaScript
  • Baseline
  • Blog
  • Case Studies
  • Welcome to Learn Performance!
  • Why speed matters
  • General HTML performance considerations
  • Understanding the critical path
  • Optimize resource loading
  • Assist the browser with resource hints
  • Image performance
  • Video performance
  • Optimize web fonts
  • Code-split JavaScript
  • Lazy load images and

webpack

webpack ships with a plugin named SplitChunksPlugin, which lets you configure how the bundler splits JavaScript files. webpack recognizes both the dynamic import() and static import statements. The behavior of SplitChunksPlugin can be modified by specifying the chunks option in its configuration:

  • chunks: async is the default value, and refers to dynamic import() calls.
  • chunks: initial refers to static import calls.
  • chunks: all covers both dynamic import() and static imports, allowing you to share chunks between async and initial imports.

By default, whenever webpack encounters a dynamic import() statement. it creates a separate chunk for that module:

/* main.js */

// An application-specific chunk required during the initial page load:
import myFunction from './my-function.js';

myFunction('Hello world!');

// If a specific condition is met, a separate chunk is downloaded on demand,
// rather than being bundled with the initial chunk:
if (condition) {
  // Assumes top-level await is available. More info:
  // https://v8.dev/features/top-level-await
  await import('/form-validation.js');
}

The default webpack configuration for the preceding code snippet results in two separate chunks:

  • The main.js chunk—which webpack classifies as an initial chunk—that includes main.js and ./my-function.js module.
  • The async chunk, which includes only form-validation.js (containing a file hash in the resource name if configured). This chunk is only downloaded if and when condition is truthy.

This configuration lets you defer loading the form-validation.js chunk until it's actually needed. This can improve load responsiveness by reducing script evaluation time during the initial page load. Script download and evaluation for the form-validation.js chunk occurs when a specified condition is met, in which case, the dynamically imported module is downloaded. One example may be a condition where a polyfill is only downloaded for a particular browser, or—as in the earlier example—the imported module is necessary for a user interaction.

On the other hand, changing the SplitChunksPlugin configuration to specify chunks: initial ensures that code is split only on initial chunks. These are chunks such as those statically imported, or listed in webpack's entry property. Looking at the preceding example, the resulting chunk would be a combination of form-validation.js and main.js in a single script file, resulting in potentially worse initial page load performance.

The options for SplitChunksPlugin can also be configured to separate larger scripts into multiple smaller ones—for example by using the maxSize option to instruct webpack to split chunks into separate files if they exceed what is specified by maxSize. Dividing large script files into smaller files can improve load responsiveness, as in some cases CPU-intensive script evaluation work is divided into smaller tasks, which are less likely to block the main thread for longer periods of time.

Additionally, generating larger JavaScript files also means that scripts are more likely to suffer from cache invalidation. For example, if you ship a very large script with both framework and first-party application code, the entire bundle can be invalidated if only the framework is updated, but nothing else in the bundled resource.

On the other hand, smaller script files increases the likelihood that a return visitor retrieves resources from the cache, resulting in faster page loads on repeat visits. However, smaller files benefit less from compression than larger ones, and may increase network round-trip time on page loads with an unprimed browser cache. Care must be taken to strike a balance between caching efficiency, compression effectiveness, and script evaluation time.

Caution: If you disable SplitChunksPlugin by specifying splitChunks: false in your application's webpack configuration, then ./my-function.js gets bundled in both main.js and form-validation.js.

webpack demo

Note: Since this demo uses a bundler, a Glitch demo can't be embedded for it. To run it, clone the following Github repository to your local machine and follow the instructions in the repository's README.

webpack SplitChunksPlugin demo.

Test your knowledge

Which type of import statement is used when performing code splitting?

Dynamic import().
Correct!
Static import.
Try again.

Which type of import statement must be at the top of a JavaScript module, and in no other location?

Dynamic import().
Try again.
Static import.
Correct!

When using SplitChunksPlugin in webpack, what is the difference between an async chunk and an initial chunk?

async chunks are loaded using dynamic import() and initial chunks are loaded using static import.
Correct!
async chunks are loaded using static import and initial chunks are loaded using dynamic import().
Try again.

Up next: Lazy load images and