Load heavy code on demand
Keep editors, charts and 3D out of the main bundle; import() on use.
From nextjs-pagespeed.
The same page, two bundles
Press Reload, then click Open editor in both panes.
Static importBad
- Editor JS at load
- —
- Blocking time at load
- —
- Button responds from
- —
- Click → editor
- —
import { Editor } from "./editor"
Dynamic importGood
- Editor JS at load
- —
- Blocking time at load
- —
- Button responds from
- —
- Click → editor
- —
dynamic(() => import("./editor"))
"use client";
import dynamic from "next/dynamic";
import { useState } from "react";
import { EditorSkeleton } from "./editor-skeleton";
// Own chunk, fetched the first time <Editor> renders
const Editor = dynamic(() => import("./editor").then((m) => m.Editor), {
ssr: false,
loading: () => <EditorSkeleton />,
});
export function Notes() {
const [open, setOpen] = useState(false);
return (
<>
<button type="button" onClick={() => setOpen((o) => !o)}>Open editor</button>
{open && <Editor />}
</>
);
}
Start the import on intent
Hover or press each Open chart button, then release.
import() on clickFine
- Head start
- —
- Wait after click
- —
import() on intentBest
- Head start
- —
- Wait after click
- —
// Same specifier as dynamic(): the click reuses the in-flight request
const preload = () => void import("./chart");
<button
type="button"
onPointerEnter={preload}
onFocus={preload}
onPointerDown={preload} // touch has no hover
onClick={() => setOpen(true)}
>
Open chart
</button>
Reserve the space it will take
Press Load page and watch the paragraph below.
One-line “Loading…”Bad
Q3 revenue
September closed at 90, the best month this year. Recurring revenue made up most of the gain.
Churn stayed flat.
CLS—
Skeleton at final sizeGood
Q3 revenue
September closed at 90, the best month this year. Recurring revenue made up most of the gain.
Churn stayed flat.
CLS—
const Chart = dynamic(() => import("./chart"), {
loading: () => <div className="chart-slot" aria-busy="true" />,
});
.chart-slot { block-size: 170px; }
Why it matters, pros and cons
Why it matters
Every first-load byte is parsed by every visitor, and the first tap waits.
Pros
- Less first-load JS, fewer long tasks.
- Only feature users pay, once.
- Prefetch on intent hides most waiting.
Cons
- First open waits a round trip without prefetch.
- An unsized placeholder trades blocking time for shift.
- Small modules cost more as a separate request.