ReviseAlgo Logo

Performance

Code Splitting

Master React code splitting, covering dynamic imports, route-based bundle splitting, bundle analysis, and performance optimization.

Last Updated: July 15, 2026 11 min read

1. Learning Objectives

In this lesson, you will learn how to optimize bundle delivery using code splitting. By the end of this topic, you will be able to:

  • Describe how web bundlers compile and optimize Javascript assets.
  • Implement route-based code splitting inside routing trees.
  • Differentiate route-based splitting from component-based dynamic loading.
  • Analyze bundle size maps using visualization tools (Rollup/Webpack).
  • Configure vendor chunk splits to improve browser caching.

2. Overview

Modern React applications rely on bundlers (like Vite, Webpack, or Rollup) to merge all code files into a single, large JavaScript bundle. **Code Splitting** tells the bundler to split this large file into multiple smaller chunks that can be downloaded dynamically on demand, speeding up initial page loads.

3. Why This Topic Matters

Managing bundle sizes is critical for keeping load times fast as applications grow:

  • Monolithic Bundles: As you add features and third-party libraries, your single bundle size increases. This causes slow initial page loads, especially on mobile devices or slow networks.
  • Optimal Caching: Splitting third-party libraries (like Lodash or Chart.js) into separate vendor chunks allows the browser to cache them permanently, since library code changes less frequently than application code.

4. Real-World Analogy

Think of code splitting like **loading a moving truck**:

  • Monolithic Bundling: Packing every single belonging—including seasonal gear, winter clothes, and guest beds—into a single massive truck. You must wait for the entire truck to be packed and delivered before you can unpack a single toothbrush.
  • Code Splitting: Packing essential items (toothbrush, bed sheets) into your car so you can settle in immediately (fast initial render). The guest beds and seasonal items are packed in secondary containers and shipped later, arriving only when they are needed.

5. Core Concepts

Below is a comparison of Route-based and Component-based code splitting:

Property Route-based Code Splitting Component-based Code Splitting
Split Target Applied to route page entry points (e.g. /admin page). Applied to specific heavy widgets (e.g. modals, text editors).
Chunk Download Trigger Triggered automatically when the URL path changes. Triggered by user interactions (like clicking a button).
Use Cases Default layout splitting for separate pages. Deferring heavy libraries until explicitly used.

6. Syntax & API Reference

This example shows how to configure route-based code splitting:

7. Visual Diagram

This diagram displays how bundlers output dynamic file chunks:

8. Live Example — Full Working Code

Below is a complete HTML page demonstrating simulated route-based code splitting and chunk loading indicators:

What just happened? Clicking "Admin" triggers the lazy loading of LazyAdmin. Because it is wrapped in `Suspense`, React displays the "Downloading page bundle chunk..." fallback UI while loading the code. Once the module resolves, it renders the admin panel page.

9. Interactive Playground

Try It Yourself Challenges:

  1. Change the timeout delay in the dynamic import simulation to 3 seconds to see how the loading state behaves.
  2. Modify the layout to add a dynamic import for a heavy library mock (e.g. importing utility formulas on demand).

10. Common Mistakes

Mistake Why it happens Wrong Correct
Over-splitting minor components Every dynamic import compiles into a separate network request. Splitting small, simple components (under 5 KB) creates too many small requests, increasing HTTP overhead and slowing down the site. Lazy loading small button icons or header text. Only split large page components (routes) or heavy third-party libraries (e.g. charts, text editors).
Omitting chunk loading error handlers If a user is browsing on a poor connection or the site is redeployed (meaning old chunk filenames no longer exist on the server), dynamic imports will fail. Without error boundaries, this crashes the app. Rendering route-based split components without an ErrorBoundary. Wrap dynamic components in an ErrorBoundary that prompts the user to refresh their browser on chunk load failures.

11. Best Practices

  • Use Route-Based Splitting: Always start code splitting at the route level to divide the application into logical page chunks.
  • Split Large Libraries: Use dynamic imports (`import('library')`) inside event handlers to load heavy libraries (like chart components or file exporters) only when the user clicks the action.
  • Analyze Bundle Maps: Regularly analyze bundle maps using tools like `rollup-plugin-visualizer` (Vite) or `webpack-bundle-analyzer` to identify and optimize large chunks.
  • Add chunk error recovery: Catch chunk load errors in your Error Boundary to prompt the user to reload the page, ensuring they load the latest assets.

12. Browser Compatibility/Requirements

Dynamic imports require browser support for ES modules.

13. Interview Questions

Q1: How do modern bundlers compile dynamic imports into separate chunks behind the scenes?

Answer: When a bundler (like Vite or Webpack) detects a dynamic `import('./MyComponent')` statement, it treats the module as a split boundary. Instead of compiling it into the main bundle, the bundler creates a separate JavaScript chunk file. At runtime, when the dynamic import runs, the browser requests this chunk file over HTTP, loading it into memory on demand.

Q2: How do you identify large modules in your bundle? Discuss rollup and webpack bundle analyzers.

Answer: You can identify large modules by running bundle analyzers (like `rollup-plugin-visualizer` in Vite or `webpack-bundle-analyzer` in Webpack). These plugins generate an interactive HTML treemap of your build outputs, visualizing files as blocks where block sizes are proportional to their raw or zipped byte weights. This makes it easy to spot heavy third-party libraries or duplicate packages.

14. Debugging Exercise

Identify why the third-party PDF editor library continues to compile into the main index bundle, slowing down the page load:

View Solution

Diagnosis: The library is imported using a static import statement (import) at the top of the file. This tells the bundler to compile the library directly into the main entry bundle, even though it is only used inside the click handler.

Fix: Change the import to a dynamic import inside the click handler to load the library on demand:

15. Practice Exercises

Exercise 1: Configure route-based code splitting

Set up a routing tree containing /catalog and /checkout routes. Configure these pages to load using route-based code splitting with custom loading fallbacks.

16. Scenario-Based Challenge

The Multi-page Admin Analytics Optimization Project:

You are designing a portal that uses heavy drawing libraries on the `/admin/analytics` page. General users do not visit this page, but they still pay the download cost of these charting libraries. Describe how you would configure code splitting to split this route and its libraries into a separate chunk.

17. Quick Quiz

Q1: What does the dynamic import() function return in JavaScript?

A) The resolved module exports object directly.

B) A Promise that resolves to the module namespace object.

C) An HTML5 script tag element.

Answer: B — Dynamic imports return a Promise that resolves to the module namespace object, allowing asynchronous code loading.

18. Summary & Key Takeaways

  • Code splitting divides monolithic javascript bundles into smaller chunks.
  • Use dynamic imports (`import()`) to load modules on demand.
  • Apply route-based splitting to decrease initial page load times.
  • Use bundle analyzers to find and optimize large packages.
  • Always handle chunk load errors in a boundary wrapper to prevent app crashes.

19. Cheat Sheet

Bundler / Split Pattern Description
const Page = lazy(() => import('./P')); Imports page modules dynamically for route splitting.
const lib = await import('lib'); Imports libraries on demand inside actions or functions.
rollup-plugin-visualizer Rollup/Vite plugin used to analyze and visualize bundle sizes.
---