DEV Community

Cover image for How to Improve the Performance of Your React App with Code Splitting
Ayush Kumar Vishwakarma
Ayush Kumar Vishwakarma

Posted on

How to Improve the Performance of Your React App with Code Splitting

As React applications grow in size and complexity, the size of their JavaScript bundles can significantly impact performance, especially on slower networks or devices. One effective way to mitigate this issue is through code splitting, a technique that breaks your application into smaller chunks. These chunks are loaded on demand, reducing the initial load time and improving overall performance.

In this article, we’ll explore what code splitting is, why it’s important, and how to implement it effectively in a React app.

What is Code Splitting?
Code splitting is a strategy used to divide your JavaScript code into smaller bundles that can be loaded dynamically when needed. Instead of delivering one large JavaScript file to the browser, code splitting allows you to send only the parts of the code that are immediately required for the user’s interaction. This reduces the app’s initial load time.

React uses dynamic imports and tools like Webpack to enable code splitting.

Benefits of Code Splitting

  1. Reduced Initial Load Time: Only critical code is loaded upfront.
  2. Improved Performance: Smaller bundles load faster, especially on slow networks.
  3. Efficient Resource Usage: Resources are loaded as needed, minimizing unused code.
  4. Better User Experience: Users experience faster interactions with your app.
  5. Implementing Code Splitting in React

1. Using React’s React.lazy and Suspense
React provides React.lazy to load components lazily, and Suspense to display fallback UI while the lazy-loaded components are being fetched.

Here’s an example:
Step 1: Lazy Load a Component

import React, { Suspense } from 'react';

// Lazy load the component
const LazyLoadedComponent = React.lazy(() => import('./LazyLoadedComponent'));

function App() {
  return (
    <div>
      <h1>React Code Splitting Example</h1>
      <Suspense fallback={<div>Loading...</div>}>
        <LazyLoadedComponent />
      </Suspense>
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • React.lazy(() => import('./LazyLoadedComponent')): Dynamically imports the component only when it’s needed.
  • <Suspense fallback={<div>Loading...</div>}>: Displays the fallback UI (e.g., a loading spinner) while the component is being loaded.

2. Code Splitting by Routes
For larger applications, splitting code by route is one of the most effective ways to improve performance. Libraries like React Router make this process seamless.

Step 1: Install React Router

npm install react-router-dom
Enter fullscreen mode Exit fullscreen mode

Step 2: Implement Code Splitting with Routes

import React, { Suspense } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';

// Lazy load components for routes
const Home = React.lazy(() => import('./Home'));
const About = React.lazy(() => import('./About'));
const Contact = React.lazy(() => import('./Contact'));

function App() {
  return (
    <Router>
      <Suspense fallback={<div>Loading...</div>}>
        <Switch>
          <Route exact path="/" component={Home} />
          <Route path="/about" component={About} />
          <Route path="/contact" component={Contact} />
        </Switch>
      </Suspense>
    </Router>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Benefits:

  • Only the JavaScript for the active route is loaded.
  • Reduces the size of the initial bundle.

3. Using Webpack’s Dynamic Imports
If you’re using Webpack as your module bundler, it supports dynamic imports out of the box. Webpack splits the code into chunks that can be loaded dynamically.

Here’s how to use it in a React app:

Example:

function loadComponent() {
  import('./HeavyComponent')
    .then((module) => {
      const Component = module.default;
      // Use the component here
    })
    .catch((error) => {
      console.error('Error loading the component:', error);
    });
}
Enter fullscreen mode Exit fullscreen mode

How it Works:

  • Webpack creates a separate chunk for HeavyComponent.
  • The chunk is loaded only when loadComponent() is called.

4. Analyzing Your Bundle with Webpack Bundle Analyzer
Before implementing code splitting, it’s essential to understand what’s contributing to your bundle size. Webpack provides a tool called Bundle Analyzer to visualize the contents of your bundles.

Step 1: Install Webpack Bundle Analyzer

npm install --save-dev webpack-bundle-analyzer
Enter fullscreen mode Exit fullscreen mode

Step 2: Configure Webpack
Add the plugin to your Webpack configuration:

const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');

module.exports = {
  plugins: [
    new BundleAnalyzerPlugin(),
  ],
};
Enter fullscreen mode Exit fullscreen mode

Step 3: Analyze Your Bundle

Run the build command to generate the report:

npm run build
Enter fullscreen mode Exit fullscreen mode

The analyzer will display a tree map showing the size of each module, helping you identify opportunities for optimization.

5. Using Third-Party Libraries with Code Splitting
Large third-party libraries (e.g., lodash, moment.js) can bloat your bundle size. You can split these libraries into separate chunks or use tree-shaking to remove unused parts of the library.

Example: Dynamic Import for a Library

import('lodash')
  .then((_) => {
    const uniq = _.uniq([1, 2, 2, 3]);
    console.log(uniq);
  })
  .catch((error) => {
    console.error('Error loading lodash:', error);
  });
Enter fullscreen mode Exit fullscreen mode

Tree-Shaking Example:
Instead of importing the entire library:

import { uniq } from 'lodash';
Enter fullscreen mode Exit fullscreen mode

Best Practices for Code Splitting

  1. Start with Route-Based Splitting: It's the easiest and most effective way to reduce initial load times.
  2. Avoid Over-Splitting: Too many chunks can lead to excessive HTTP requests.
  3. Combine Code Splitting with Lazy Loading: Load only what is necessary for the current user interaction.
  4. Monitor Performance: Use tools like Lighthouse to measure improvements after implementing code splitting.
  5. Use Modern Build Tools: Tools like Webpack, Vite, and Parcel offer built-in support for code splitting.

Conclusion
Code splitting is a powerful optimization technique that can drastically improve the performance of your React applications. By dividing your app into smaller chunks and loading them on demand, you can reduce initial load times, improve user experience, and make your app more efficient.

Start with route-based splitting and then experiment with component-level or library-level splitting to tailor the optimization to your app's needs. Combine code splitting with other performance techniques, like lazy loading and tree-shaking, to maximize your React app's efficiency.

Top comments (0)