The SplitChunksPlugin allows you to split your code into separate chunks. This improves caching by separating vendor code from application code and enables parallel loading of resources.
This plugin is included by default in webpack and enabled automatically when using optimization.splitChunks.
Basic Usage
module.exports = {
optimization: {
splitChunks: {
chunks: 'all'
}
}
};
Default Configuration
Webpack provides sensible defaults:
module.exports = {
optimization: {
splitChunks: {
chunks: 'async',
minSize: 20000,
minRemainingSize: 0,
minChunks: 1,
maxAsyncRequests: 30,
maxInitialRequests: 30,
enforceSizeThreshold: 50000,
cacheGroups: {
defaultVendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10,
reuseExistingChunk: true
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
}
}
};
Configuration Options
chunks
string | function
default:"'async'"
Which chunks to optimize:
'all' - All chunks
'async' - Only async chunks
'initial' - Only initial chunks
- Function for custom logic
Minimum size (in bytes) for a chunk to be generated
Minimum number of chunks that must share a module before splitting
Maximum number of parallel requests for async chunks
Maximum number of parallel requests for initial chunks
Define custom cache groups for splitting logic
Examples
Separate Vendor Code
module.exports = {
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
}
};
Split by Library
module.exports = {
optimization: {
splitChunks: {
cacheGroups: {
react: {
test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
name: 'react',
chunks: 'all'
},
lodash: {
test: /[\\/]node_modules[\\/]lodash[\\/]/,
name: 'lodash',
chunks: 'all'
},
commons: {
test: /[\\/]node_modules[\\/]/,
name: 'commons',
chunks: 'all'
}
}
}
}
};
Shared Modules
module.exports = {
optimization: {
splitChunks: {
cacheGroups: {
shared: {
name: 'shared',
minChunks: 2,
chunks: 'all',
priority: 10,
reuseExistingChunk: true,
enforce: true
}
}
}
}
};
Split All Chunks
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
name: false // Keep original chunk names
}
}
};
Custom Chunk Names
module.exports = {
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name(module) {
// Get package name
const packageName = module.context.match(
/[\\/]node_modules[\\/](.*?)(?:[\\/]|$)/
)[1];
return `npm.${packageName.replace('@', '')}`;
},
chunks: 'all'
}
}
}
}
};
Size-Based Splitting
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
minSize: 10000,
maxSize: 250000,
cacheGroups: {
default: false,
vendors: false,
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendor',
chunks: 'all',
priority: 20
},
common: {
minChunks: 2,
priority: 10,
reuseExistingChunk: true
}
}
}
}
};
Cache Groups
Cache groups define how modules are grouped into chunks:
cacheGroups: {
myGroup: {
test: /[\\/]src[\\/]components[\\/]/, // Which modules
name: 'components', // Chunk name
chunks: 'all', // Which chunks
priority: 10, // Priority
reuseExistingChunk: true, // Reuse existing chunks
enforce: true // Ignore size limits
}
}
Cache Group Options
test
RegExp | string | function
Condition to match modules
Priority when multiple cache groups match
Reuse existing chunk if it contains all modules
Ignore minSize, minChunks, and other size constraints
Advanced Patterns
Dynamic Imports
// Your code
import(/* webpackChunkName: "lodash" */ 'lodash').then(_ => {
// Use lodash
});
// Configuration
module.exports = {
optimization: {
splitChunks: {
chunks: 'async', // Split async chunks
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendor-async',
chunks: 'async'
}
}
}
}
};
CSS Splitting
module.exports = {
optimization: {
splitChunks: {
cacheGroups: {
styles: {
name: 'styles',
type: 'css/mini-extract',
chunks: 'all',
enforce: true
}
}
}
}
};
Conditional Splitting
const isProduction = process.env.NODE_ENV === 'production';
module.exports = {
optimization: {
splitChunks: isProduction
? {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
: false // Disable in development
}
};
Multiple Entry Points
module.exports = {
entry: {
home: './src/home.js',
admin: './src/admin.js'
},
optimization: {
splitChunks: {
cacheGroups: {
commons: {
name: 'commons',
chunks: 'initial',
minChunks: 2 // Shared between both entries
}
}
}
}
};
Benefits of code splitting:
- Better caching (vendor code changes less frequently)
- Parallel loading (multiple chunks load simultaneously)
- Reduced initial bundle size
- Faster page loads with lazy loading
Example
Before splitting:
- app.js: 2.5 MB (changes frequently)
After splitting:
- vendor.js: 1.8 MB (changes rarely, cached)
- app.js: 700 KB (changes frequently)
Result: Most visits only download 700 KB
Debugging
Analyze bundle composition:
npm install --save-dev webpack-bundle-analyzer
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
plugins: [
new BundleAnalyzerPlugin()
]
};
Best Practices
-
Start Simple
splitChunks: { chunks: 'all' }
-
Separate Vendor Code
- Vendors change less frequently
- Better caching
- Smaller app bundle
-
Use Meaningful Names
name: 'vendor-react' // Not just 'vendor'
-
Consider Size Limits
minSize: 30000, // 30 KB minimum
maxSize: 250000 // 250 KB maximum
-
Balance Chunk Count
- Too many chunks = too many requests
- Too few chunks = large downloads
- Aim for 3-7 chunks for most apps
Splitting too aggressively can increase the number of HTTP requests, potentially slowing down load times on HTTP/1.1. Consider your target environment.