阿里云主机折上折
  • 微信号
Current Site:Index > Build a speed measurement and analysis tool

Build a speed measurement and analysis tool

Author:Chuan Chen 阅读数:51573人阅读 分类: 构建工具

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:

  1. Total Build Time: The complete build duration from start to finish.
  2. Time Consumption by Phase:
    • Initialization phase
    • Compilation phase
    • Module building
    • Dependency analysis
    • Optimization phase
    • Resource generation
  3. Plugin/Loader Time Consumption: Execution time of each plugin and loader.
  4. 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

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.