Tree Shaking Configuration - Complete Guide
Published: September 25, 2024 | Reading time: 20 minutes
Tree Shaking Overview
Tree shaking eliminates unused code from bundles:
Tree Shaking Benefits
# Tree Shaking Benefits
- Smaller bundle sizes
- Dead code elimination
- Better performance
- Reduced loading times
- Improved user experience
- Lower bandwidth usage
- Better caching
Webpack Tree Shaking
Webpack Configuration
Webpack Tree Shaking
# Webpack Tree Shaking
# 1. Basic Tree Shaking Configuration
# webpack.config.js
module.exports = {
mode: 'production',
optimization: {
usedExports: true,
sideEffects: false,
},
};
# 2. Advanced Tree Shaking
# webpack.config.js
module.exports = {
mode: 'production',
optimization: {
usedExports: true,
sideEffects: false,
concatenateModules: true,
providedExports: true,
},
};
# 3. Side Effects Configuration
# package.json
{
"sideEffects": false
}
# 4. Specific Side Effects
# package.json
{
"sideEffects": [
"*.css",
"*.scss",
"*.sass",
"*.less"
]
}
# 5. Module Resolution
# webpack.config.js
module.exports = {
resolve: {
mainFields: ['browser', 'module', 'main'],
},
};
# 6. ES6 Module Support
# webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
['@babel/preset-env', {
modules: false,
}],
],
},
},
},
],
},
};
# 7. Tree Shaking with TypeScript
# webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.ts$/,
exclude: /node_modules/,
use: {
loader: 'ts-loader',
options: {
compilerOptions: {
module: 'esnext',
moduleResolution: 'node',
},
},
},
},
],
},
};
# 8. Tree Shaking with React
# webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
['@babel/preset-env', {
modules: false,
}],
['@babel/preset-react', {
runtime: 'automatic',
}],
],
},
},
},
],
},
};
# 9. Tree Shaking with Lodash
# webpack.config.js
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
module.exports = {
plugins: [
new LodashModuleReplacementPlugin(),
],
};
# 10. Tree Shaking Analysis
# webpack.config.js
module.exports = {
optimization: {
usedExports: true,
sideEffects: false,
},
stats: {
usedExports: true,
providedExports: true,
optimizationBailout: true,
},
};
ES6 Module Optimization
Module Import Strategies
ES6 Module Optimization
# ES6 Module Optimization
# 1. Named Imports
# Good for tree shaking
import { debounce, throttle } from 'lodash-es';
# 2. Default Imports
# Good for tree shaking
import React from 'react';
import { Component } from 'react';
# 3. Namespace Imports
# Bad for tree shaking
import * as _ from 'lodash';
# 4. Destructuring Imports
# Good for tree shaking
import { map, filter, reduce } from 'lodash-es';
# 5. Re-export Patterns
# utils/index.js
export { debounce } from './debounce';
export { throttle } from './throttle';
export { map } from './map';
# 6. Conditional Imports
# utils/conditional.js
export const loadUtility = (name) => {
switch (name) {
case 'debounce':
return import('./debounce').then(m => m.debounce);
case 'throttle':
return import('./throttle').then(m => m.throttle);
default:
return Promise.resolve(null);
}
};
# 7. Dynamic Imports
# utils/dynamic.js
export const loadComponent = (name) => {
return import(`./components/${name}`).then(m => m.default);
};
# 8. Barrel Exports
# components/index.js
export { Button } from './Button';
export { Input } from './Input';
export { Modal } from './Modal';
# 9. Tree Shaking Friendly Imports
# Good
import { debounce } from 'lodash-es';
import { Button } from './components';
# Bad
import _ from 'lodash';
import * as components from './components';
# 10. Module Resolution
# webpack.config.js
module.exports = {
resolve: {
alias: {
'lodash': 'lodash-es',
},
},
};
Library Tree Shaking
Third-Party Library Optimization
Library Tree Shaking
# Library Tree Shaking
# 1. Lodash Tree Shaking
# Install lodash-es
npm install lodash-es
# Use specific imports
import { debounce, throttle } from 'lodash-es';
# 2. Moment.js Tree Shaking
# Install date-fns instead
npm install date-fns
# Use specific functions
import { format, parseISO } from 'date-fns';
# 3. React Tree Shaking
# Use specific imports
import { useState, useEffect } from 'react';
# 4. Material-UI Tree Shaking
# Use specific imports
import { Button, TextField } from '@mui/material';
# 5. Ant Design Tree Shaking
# Use specific imports
import { Button, Input } from 'antd';
# 6. Bootstrap Tree Shaking
# Use specific imports
import 'bootstrap/dist/css/bootstrap.min.css';
import { Modal } from 'bootstrap';
# 7. Chart.js Tree Shaking
# Use specific imports
import { Chart, registerables } from 'chart.js';
Chart.register(...registerables);
# 8. D3.js Tree Shaking
# Use specific imports
import { select, scaleLinear } from 'd3';
# 9. RxJS Tree Shaking
# Use specific imports
import { Observable, Subject } from 'rxjs';
# 10. Custom Library Tree Shaking
# utils/index.js
export { debounce } from './debounce';
export { throttle } from './throttle';
# Use specific imports
import { debounce } from './utils';
Tree Shaking Best Practices
Optimization Guidelines
Best Practices
- Use ES6 modules
- Specific imports
- Avoid namespace imports
- Configure side effects
- Use tree-shaking friendly libraries
- Enable production mode
- Monitor bundle size
Common Mistakes
- Namespace imports
- CommonJS modules
- Side effects in modules
- Non-tree-shaking libraries
- Missing production mode
- Poor import patterns
- Missing side effects config
Tree Shaking Analysis
Monitoring and Debugging
Tree Shaking Analysis
# Tree Shaking Analysis
# 1. Webpack Bundle Analyzer
npm install --save-dev webpack-bundle-analyzer
# webpack.config.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
plugins: [
new BundleAnalyzerPlugin({
analyzerMode: 'server',
openAnalyzer: true,
}),
],
};
# 2. Source Map Explorer
npm install --save-dev source-map-explorer
npx source-map-explorer 'dist/*.js'
# 3. Webpack Stats
# webpack.config.js
module.exports = {
stats: {
usedExports: true,
providedExports: true,
optimizationBailout: true,
reasons: true,
modules: true,
chunks: true,
},
};
# 4. Tree Shaking Report
# tree-shaking-report.js
const fs = require('fs');
const path = require('path');
function analyzeTreeShaking() {
const bundlePath = path.join(__dirname, 'dist', 'main.js');
const content = fs.readFileSync(bundlePath, 'utf8');
// Analyze unused code
const unusedPatterns = [
/\/\* unused \*\//g,
/\/\* harmony export \*\//g,
];
let unusedCount = 0;
unusedPatterns.forEach(pattern => {
const matches = content.match(pattern);
if (matches) {
unusedCount += matches.length;
}
});
console.log(`Unused code patterns found: ${unusedCount}`);
}
analyzeTreeShaking();
# 5. Bundle Size Comparison
# compare-bundles.js
const fs = require('fs');
const path = require('path');
function getBundleSize(filePath) {
const stats = fs.statSync(filePath);
return Math.round(stats.size / 1024);
}
const currentSize = getBundleSize('dist/main.js');
const previousSize = getBundleSize('dist-previous/main.js');
const difference = currentSize - previousSize;
console.log(`Current bundle: ${currentSize} KB`);
console.log(`Previous bundle: ${previousSize} KB`);
console.log(`Difference: ${difference} KB`);
# 6. Tree Shaking Validation
# validate-tree-shaking.js
const fs = require('fs');
const path = require('path');
function validateTreeShaking() {
const bundlePath = path.join(__dirname, 'dist', 'main.js');
const content = fs.readFileSync(bundlePath, 'utf8');
// Check for tree shaking markers
const treeShakingMarkers = [
'/* unused harmony export',
'/* harmony export',
'/* unused harmony import',
];
let markerCount = 0;
treeShakingMarkers.forEach(marker => {
const matches = content.match(new RegExp(marker, 'g'));
if (matches) {
markerCount += matches.length;
}
});
console.log(`Tree shaking markers found: ${markerCount}`);
}
validateTreeShaking();
# 7. CI/CD Tree Shaking Check
# .github/workflows/tree-shaking.yml
name: Tree Shaking Check
on: [push, pull_request]
jobs:
tree-shaking:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
- run: npm ci
- run: npm run build
- run: npm run analyze
# 8. Tree Shaking Metrics
# metrics.js
const fs = require('fs');
const path = require('path');
function getTreeShakingMetrics() {
const bundlePath = path.join(__dirname, 'dist', 'main.js');
const stats = fs.statSync(bundlePath);
const sizeInKB = Math.round(stats.size / 1024);
const metrics = {
bundleSize: sizeInKB,
timestamp: new Date().toISOString(),
treeShakingEnabled: true,
};
fs.writeFileSync('tree-shaking-metrics.json', JSON.stringify(metrics, null, 2));
}
getTreeShakingMetrics();
Summary
Tree shaking configuration involves several key components:
- Webpack Configuration: Production mode, used exports, and side effects
- ES6 Modules: Import strategies and module optimization
- Library Optimization: Third-party library tree shaking
- Analysis: Monitoring, debugging, and validation tools
Need More Help?
Struggling with tree shaking configuration or need help optimizing your bundle size? Our performance experts can help you implement effective tree shaking strategies.
Get Tree Shaking Help