Build a speed measurement and analysis tool
Why Build Speed Measurement and Analysis Tools Are Needed
Webpack build speed directly impacts development efficiency and deployment frequency. As project scale expands and the number of modules increases, build times can extend from a few seconds to several minutes or even longer. Slow build processes lead to increased developer wait times, longer iteration cycles, and ultimately affect product delivery speed. By measuring and analyzing time consumption during the build process, performance bottlenecks can be identified and targeted optimizations can be made.
Core Measurement Metrics
Build speed analysis primarily focuses on the following key metrics:
- Total Build Time: The complete build duration from start to finish.
- Time Consumption by Phase:
- Initialization phase
- Compilation phase
- Module building
- Dependency analysis
- Optimization phase
- Resource generation
- Plugin/Loader Time Consumption: Execution time of each plugin and loader.
- Module Build Time: Build duration of individual modules.
Basic Measurement Methods
The simplest measurement method is to use Webpack's built-in stats
output:
module.exports = {
//...
profile: true,
stats: {
timings: true,
reasons: true,
modules: true,
chunks: true
}
}
After running the build, you can see output similar to this in the console:
Time: 3567ms
Built at: 2023-05-01 10:00:00
Asset Size Chunks Chunk Names
main.js 1.25 MiB 0 [emitted] main
Using speed-measure-webpack-plugin
For more professional measurements, use the speed-measure-webpack-plugin
:
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const smp = new SpeedMeasurePlugin();
module.exports = smp.wrap({
// Original webpack configuration
plugins: [
new MyPlugin(),
new MyOtherPlugin()
]
});
After building, a detailed time consumption report will be output:
SMP ⏱
General output time took 3.89 secs
SMP ⏱ Plugins
MyPlugin took 1.23 secs
MyOtherPlugin took 0.45 secs
SMP ⏱ Loaders
babel-loader took 2.1 secs, 56 modules
css-loader took 0.8 secs, 23 modules
Visualization Tools
webpack-bundle-analyzer
Analyze bundle size and composition:
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
plugins: [
new BundleAnalyzerPlugin()
]
}
webpack-dashboard
Provides a more user-friendly console interface:
const DashboardPlugin = require('webpack-dashboard/plugin');
module.exports = {
//...
plugins: [
new DashboardPlugin()
]
}
Advanced Performance Analysis
Use Node.js's performance hooks for more granular measurements:
const { performance, PerformanceObserver } = require('perf_hooks');
const obs = new PerformanceObserver((items) => {
items.getEntries().forEach((entry) => {
console.log(`${entry.name}: ${entry.duration}ms`);
});
});
obs.observe({ entryTypes: ['measure'] });
performance.mark('build-start');
// Build process...
performance.mark('build-end');
performance.measure('Total Build Time', 'build-start', 'build-end');
Build Cache Strategy Analysis
Caching is an important method for improving build speed. Cache hit rates need to be analyzed:
const cacheLoader = {
loader: 'cache-loader',
options: {
cacheDirectory: path.resolve('.cache'),
cacheIdentifier: 'v1'
}
};
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: [
cacheLoader,
'babel-loader'
]
}
]
}
};
Compare build times before and after caching to analyze effectiveness:
First build: 4200ms
Build with cache: 1800ms
Multi-Process Build Analysis
Use thread-loader
to analyze the effects of multi-process building:
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: [
{
loader: 'thread-loader',
options: {
workers: 4,
workerParallelJobs: 50,
poolTimeout: 2000
}
},
'babel-loader'
]
}
]
}
};
Analyze the impact of different worker counts on build time:
1 worker: 3200ms
2 workers: 2100ms
4 workers: 1800ms
8 workers: 1700ms
Incremental Build Analysis
Performance analysis of incremental builds in development mode:
module.exports = {
watch: true,
watchOptions: {
aggregateTimeout: 300,
poll: 1000,
ignored: /node_modules/
}
};
Record rebuild times after file changes:
Initial build: 4200ms
Rebuild after modifying a single file: 800ms
Rebuild after modifying a core component: 1200ms
Custom Measurement Plugin
Develop a custom plugin to record time consumption for specific phases:
class BuildTimeAnalyzerPlugin {
apply(compiler) {
const stages = {};
compiler.hooks.compilation.tap('BuildTimeAnalyzer', (compilation) => {
compilation.hooks.buildModule.tap('BuildTimeAnalyzer', (module) => {
stages[module.identifier()] = {
start: Date.now()
};
});
compilation.hooks.succeedModule.tap('BuildTimeAnalyzer', (module) => {
stages[module.identifier()].end = Date.now();
});
});
compiler.hooks.done.tap('BuildTimeAnalyzer', (stats) => {
const slowModules = Object.entries(stages)
.map(([id, time]) => ({
id,
duration: time.end - time.start
}))
.sort((a, b) => b.duration - a.duration)
.slice(0, 5);
console.log('Slowest modules:', slowModules);
});
}
}
Environment Difference Analysis
Compare build performance across different environments:
// webpack.dev.js
module.exports = {
mode: 'development',
devtool: 'eval-source-map'
};
// webpack.prod.js
module.exports = {
mode: 'production',
devtool: 'source-map'
};
Record build times for each environment:
Development environment: 3200ms
Production environment: 5800ms
Long-Term Trend Monitoring
Establish historical records of build performance:
const fs = require('fs');
const path = require('path');
class BuildTimeTrackerPlugin {
constructor() {
this.filePath = path.resolve('build-stats.json');
}
apply(compiler) {
compiler.hooks.done.tap('BuildTimeTracker', (stats) => {
const data = {
date: new Date().toISOString(),
duration: stats.toJson().time,
hash: stats.hash
};
let history = [];
if (fs.existsSync(this.filePath)) {
history = JSON.parse(fs.readFileSync(this.filePath));
}
history.push(data);
fs.writeFileSync(this.filePath, JSON.stringify(history, null, 2));
});
}
}
Build Resource Configuration Analysis
Analyze resource usage during the build process:
const os = require('os');
class ResourceUsagePlugin {
apply(compiler) {
const startCpu = os.cpus();
const startMem = process.memoryUsage();
compiler.hooks.done.tap('ResourceUsage', () => {
const endCpu = os.cpus();
const endMem = process.memoryUsage();
console.log('CPU usage:', calculateCpuDiff(startCpu, endCpu));
console.log('Memory usage:', {
rss: (endMem.rss - startMem.rss) / 1024 / 1024 + 'MB',
heapTotal: (endMem.heapTotal - startMem.heapTotal) / 1024 / 1024 + 'MB',
heapUsed: (endMem.heapUsed - startMem.heapUsed) / 1024 / 1024 + 'MB'
});
});
}
}
function calculateCpuDiff(start, end) {
// CPU calculation logic...
}
Git-Based Build Analysis
Correlate build performance with code changes:
const { execSync } = require('child_process');
class GitBuildAnalyzerPlugin {
apply(compiler) {
let gitInfo = {};
try {
gitInfo = {
branch: execSync('git rev-parse --abbrev-ref HEAD').toString().trim(),
commit: execSync('git rev-parse HEAD').toString().trim(),
changes: execSync('git diff --shortstat').toString().trim()
};
} catch (e) {}
compiler.hooks.done.tap('GitBuildAnalyzer', (stats) => {
const buildData = {
...gitInfo,
duration: stats.toJson().time,
date: new Date().toISOString()
};
// Store build data
});
}
}
Build Analysis in CI Environments
Collect build metrics in continuous integration environments:
// webpack.config.ci.js
module.exports = {
plugins: [
new (class CiReporterPlugin {
apply(compiler) {
compiler.hooks.done.tap('CiReporter', (stats) => {
if (process.env.CI) {
const metrics = {
build_time: stats.toJson().time,
asset_size: stats.toJson().assets
.reduce((sum, asset) => sum + asset.size, 0),
module_count: stats.toJson().modules.length
};
// Report to CI system
fetch(process.env.CI_METRICS_URL, {
method: 'POST',
body: JSON.stringify(metrics)
});
}
});
}
})()
]
};
Build Process Optimization Suggestions
A plugin that provides optimization suggestions based on analysis results:
class OptimizationAdvisorPlugin {
apply(compiler) {
compiler.hooks.done.tap('OptimizationAdvisor', (stats) => {
const json = stats.toJson();
const suggestions = [];
if (json.time > 5000) {
suggestions.push('Build time exceeds 5 seconds. Consider using cache-loader or hard-source-webpack-plugin');
}
const largeModules = json.modules
.filter(m => m.size > 50000)
.slice(0, 3);
if (largeModules.length) {
suggestions.push(
`Large modules detected: ${largeModules.map(m => m.name).join(', ')}, consider code splitting`
);
}
if (suggestions.length) {
console.log('Optimization suggestions:\n- ' + suggestions.join('\n- '));
}
});
}
}
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
下一篇:多进程/多实例构建方案