Skip to main content
Code splitting allows you to split your code into various bundles which can then be loaded on demand or in parallel. This reduces initial load time and improves performance.

Why Code Splitting?

Code splitting helps you:
  • Reduce initial bundle size
  • Load code on demand
  • Improve page load performance
  • Better utilize browser caching

Dynamic Imports

The most common way to implement code splitting is through dynamic import() syntax.
1

Use dynamic imports

Instead of static imports, use dynamic import() to split code:Before:
import moduleA from 'a';
import moduleB from 'b';
After:
import('a').then(moduleA => {
  // Use moduleA
});

// Or with async/await
const moduleB = await import('b');
2

Configure optimization

Add chunk optimization to your webpack config:
module.exports = {
  optimization: {
    chunkIds: 'named', // Use readable chunk names
    splitChunks: {
      chunks: 'all'
    }
  }
};
3

Name your chunks

Use magic comments to name chunks:
import(/* webpackChunkName: "my-chunk" */ './module').then(module => {
  // Module loaded
});

Entry Points

Split code by defining multiple entry points:
module.exports = {
  entry: {
    main: './src/index.js',
    admin: './src/admin.js',
    vendor: './src/vendor.js'
  },
  output: {
    filename: '[name].bundle.js'
  }
};

SplitChunksPlugin

Webpack’s built-in SplitChunksPlugin automatically splits chunks based on conditions:
module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all',
      minSize: 20000,
      maxSize: 244000,
      minChunks: 1,
      maxAsyncRequests: 30,
      maxInitialRequests: 30,
      cacheGroups: {
        defaultVendors: {
          test: /[\\/]node_modules[\\/]/,
          priority: -10,
          reuseExistingChunk: true
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true
        }
      }
    }
  }
};
The SplitChunksPlugin works out of the box with sensible defaults. You only need to configure it if you want to customize the splitting behavior.

Dynamic Import with Context

Load modules dynamically based on runtime values:
function loadComponent(name) {
  return import(`./components/${name}`);
}

Promise.all([
  loadComponent('Header'),
  loadComponent('Footer')
]).then(([Header, Footer]) => {
  // Components loaded
});
Dynamic imports with variables create a context that includes all possible modules. Be specific with your paths to avoid bundling unnecessary code.

Prefetching and Preloading

Optimize loading with resource hints:
// Prefetch - load during idle time
import(/* webpackPrefetch: true */ './future-module');

// Preload - load in parallel with parent
import(/* webpackPreload: true */ './critical-module');
Use webpackPrefetch for modules that might be needed soon, and webpackPreload for modules that are needed for the current navigation.

Common Patterns

Route-based Splitting

const routes = [
  {
    path: '/home',
    component: () => import('./views/Home')
  },
  {
    path: '/about',
    component: () => import('./views/About')
  }
];

Vendor Splitting

module.exports = {
  optimization: {
    splitChunks: {
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all'
        }
      }
    }
  }
};

Bundle Analysis

Analyze your bundles to optimize splitting:
npm install --save-dev webpack-bundle-analyzer
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
  plugins: [
    new BundleAnalyzerPlugin()
  ]
};
Run the analyzer after major changes to identify optimization opportunities and ensure your splitting strategy is effective.