Using Webpack Dynamic Imports for Code Splitting in a React App
Learn how to split non‑critical React components into separate chunks with dynamic imports, reducing initial bundle size and improving load time.
29 Jan 2026, 05:08 UTC

The problem: a large initial bundle hurts first paint
When a single-page application bundles all JavaScript into one file, the browser must download, parse, and execute that file before it can render any meaningful UI. On slower connections or low‑end devices this adds noticeable delay to the first paint, especially when parts of the app (like a modal, a dashboard widget, or a rarely‑used settings page) are not needed immediately.
Thesis: dynamic imports let webpack create on‑demand chunks that keep the initial bundle small
Webpack treats the ES2020 import() function as a split point. When it encounters import('./SomeModule.js'), it creates a separate chunk for that module and returns a Promise that resolves when the chunk is fetched. By pairing this with React.lazy and Suspense, you can declaratively load components only when they are needed.
How dynamic imports work in webpack
- Split point: The call to
import()tells webpack to treat the argument as a dynamic dependency. - Chunk naming: Adding a "magic comment" like
/* webpackChunkName: "Dashboard" */gives the generated file a readable name instead of an opaque numeric ID. - Output location: By default webpack places chunks in the same folder as the main bundle, using
output.publicPathto resolve URLs at runtime.
Worked example: lazy‑loading a dashboard widget
Assume a React project built with webpack 5. The main app renders a navigation bar and a placeholder for a dashboard that should only appear when the user clicks "Show Dashboard".
- Install the necessary dependencies (if not already present):
npm i react react-dom - Create the dashboard component (
src/Dashboard.js):import React from 'react'; export default function Dashboard() { return (Dashboard
This content is loaded on demand.
); } - In the main App file (
src/App.js) use a dynamic import with a magic comment and wrap it inReact.lazy:import React, { lazy, Suspense } from 'react'; const Dashboard = lazy(() => import(/* webpackChunkName: "Dashboard" */ './Dashboard') ); export default function App() { const [show, setShow] = React.useState(false); return ( My App setShow(true)} disabled={show}> Show Dashboard {show && ( Loading dashboard…}> )} ); } - Verify the split:
- Run the production build:
npm run build(assuming your script invokes webpack). - Inspect the output folder (
dist/orbuild/). You should see at least two files: a main bundle (e.g.,main.[hash].js) and a chunk named something likeDashboard.[hash].js. - Open the built page in Chrome, open DevTools → Network, disable cache, and reload. Initially only the main bundle is requested.
- Click the "Show Dashboard" button. A new request for the Dashboard chunk appears, and the fallback "Loading dashboard…" is replaced by the component.
- Run the production build:
Trade‑offs and limitations
- Request waterfall: If you split too many tiny modules, each triggers a separate HTTP request. On HTTP/1.1 this can add latency; even with HTTP/2, excessive small requests can compress poorly. Bundle related code together or use
webpack.SplitChunksPluginto enforce a minimum chunk size. - Error handling: A failed network request for a chunk rejects the Promise returned by
import(). You must catch errors (e.g., with a try/catch around the lazy initializer) or rely on React Error Boundaries to prevent the whole app from crashing. - Public path correctness: If
output.publicPathis misconfigured (e.g., set to a relative path when the app is served from a subdirectory), the browser will 404 when trying to fetch the chunk. Verify the value matches the deployment URL.
Actionable closing
Start by identifying a component that is not required on the initial render—a modal, a settings pane, or a heavy chart library. Replace its static import with a dynamic import, add a meaningful webpackChunkName comment, and wrap it in React.lazy and Suspense. Build, inspect the generated chunks, and confirm in the Network tab that the chunk loads only on interaction. Monitor the bundle size with webpack-bundle-analyzer to ensure you’re gaining a net reduction in initial payload without creating an excessive number of requests.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.