Skip to content

JavaScript Tutorial JavaScript Performance

Code Splitting

Lesson 225 of 258 2 min read By Deepak Paswan Updated Oct 4, 2026

If all your JavaScript is in one big file, every visitor downloads, parses and runs all of it before the page works, including code for features they may never use. Code splitting divides the code into smaller chunks that load separately and only when needed.

The idea

code
TEXT
Without splitting:   [ app.js: everything (800 KB) ]          ← loaded on every page

With splitting:      [ main.js: core (80 KB) ]                 ← loaded at start
                     [ chart.js: charts ]    ← only when a chart is shown
                     [ editor.js: editor ]   ← only on the edit page
                     [ admin.js: admin tools ] ← only for admins

(The sizes are an illustration, not measurements.)

How it is done

1. Dynamic import() marks a split point. Bundlers (Vite, webpack, esbuild, Rollup) see it and put that module in its own chunk.

script.js
JS
// main.js
button.addEventListener("click", async () => {
  const { renderChart } = await import("./chart.js");   // a separate chunk
  renderChart(data);
});

2. Route-based splitting. Each page or route gets its own bundle. This is the most common and effective split.

3. Splitting vendor code. Libraries that rarely change go in a separate file, so browsers can cache them across your releases.

Without a bundler

Native ES modules already split code at the file level: each import is its own file, loaded in parallel and cached. For small projects, that is enough. See Browser Modules.

Script loading attributes

AttributeWhen it runsUse for
(none)blocks parsing, runs immediatelyavoid
deferafter the HTML is parsed, in orderyour main scripts
asyncas soon as downloaded, any orderindependent scripts (analytics)
type="module"deferred, with importsmodern apps
index.html
HTML
<script src="analytics.js" async></script>
<script src="app.js" defer></script>

Preloading what you will need soon

Chunks can be fetched early, without running them, so they are ready when needed:

index.html
HTML
<link rel="modulepreload" href="/js/chart.js">

Or trigger a dynamic import on hover or idle time.

What to split

  • Big libraries used on a few pages (charts, editors, maps, PDF viewers).
  • Admin or rarely used features.
  • Large data sets and translations (load the user’s language only).
  • Modals and widgets that appear after interaction.

What not to split

  • Small modules (the extra request costs more than it saves).
  • Code needed to display the first screen.
  • Everything. Too many tiny chunks create waterfalls of requests.

Check the results

Use your bundler’s analyser (for example rollup-plugin-visualizer, webpack-bundle-analyzer) to see what is in each bundle, and the Network panel to see what loads when. Always measure (Measuring Performance).

info
A concept, not a requirement
Many sites never need splitting. If your JavaScript is small, simple, well deferred and cached, leave it alone and spend the time on content and accessibility.