阿里云主机折上折
  • 微信号
Current Site:Index > Build lifecycle hooks

Build lifecycle hooks

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

Build Lifecycle Hooks

Webpack's build lifecycle hooks allow developers to insert custom logic at different stages of the compilation process. These hooks are exposed through the compiler and compilation objects, covering the entire workflow from initialization to resource output. Understanding the timing and purpose of these hooks enables advanced customization of the build process.

Compiler Hooks

The compiler object represents the complete Webpack environment configuration, and its lifecycle hooks span the entire build process. Below are examples of key stages:

compiler.hooks.beforeRun.tap('MyPlugin', (compiler) => {
  console.log('Triggered before the build starts');
});

compiler.hooks.compile.tap('MyPlugin', (params) => {
  console.log('Triggered before creating a new compilation');
});

compiler.hooks.done.tap('MyPlugin', (stats) => {
  console.log('Triggered when the build completes');
});

The beforeRun hook executes immediately after reading the configuration and is suitable for initializing third-party tools. The emit stage allows modifying final resources:

compiler.hooks.emit.tapAsync('MyPlugin', (compilation, callback) => {
  compilation.assets['license.txt'] = {
    source: () => 'MIT License',
    size: () => 10
  };
  callback();
});

Compilation Hooks

The compilation object handles the construction of the module dependency graph, and its hooks provide finer-grained control:

compilation.hooks.buildModule.tap('MyPlugin', (module) => {
  console.log(`Start building module: ${module.identifier()}`);
});

compilation.hooks.succeedModule.tap('MyPlugin', (module) => {
  console.log(`Module built successfully: ${module.resource}`);
});

During the resource optimization phase, optimizeChunkAssets can be used to modify chunk content:

compilation.hooks.optimizeChunkAssets.tapAsync('MyPlugin', (chunks, callback) => {
  chunks.forEach(chunk => {
    chunk.files.forEach(file => {
      compilation.assets[file] = new ConcatSource(
        '/** Custom header **/\n',
        compilation.assets[file]
      );
    });
  });
  callback();
});

Asynchronous and Synchronous Hooks

Webpack hooks are divided into three types: synchronous (SyncHook), asynchronous serial (AsyncSeriesHook), and asynchronous parallel (AsyncParallelHook). Asynchronous hooks require the use of tapAsync or tapPromise:

// Asynchronous serial example
compiler.hooks.emit.tapAsync('MyPlugin', (compilation, callback) => {
  setTimeout(() => {
    console.log('Delayed operation');
    callback();
  }, 1000);
});

// Promise example
compiler.hooks.emit.tapPromise('MyPlugin', (compilation) => {
  return new Promise(resolve => {
    fs.writeFile('build.log', 'Build log', resolve);
  });
});

Practical Example: Resource Analysis Plugin

Combine multiple hooks to implement build resource analysis functionality:

class AnalyzePlugin {
  apply(compiler) {
    const stats = { 
      entryPoints: new Set(),
      modules: new Map()
    };

    compiler.hooks.compilation.tap('AnalyzePlugin', (compilation) => {
      compilation.hooks.addEntry.tap('AnalyzePlugin', (entry) => {
        stats.entryPoints.add(entry.name);
      });

      compilation.hooks.succeedModule.tap('AnalyzePlugin', (module) => {
        stats.modules.set(module.id, {
          size: module.size(),
          deps: Array.from(module.dependencies).map(dep => dep.module?.id)
        });
      });
    });

    compiler.hooks.done.tap('AnalyzePlugin', () => {
      fs.writeFileSync('stats.json', JSON.stringify(stats, null, 2));
    });
  }
}

Hook Execution Order

The typical build process triggers hooks in the following order:

  1. environment: Environment preparation
  2. afterEnvironment: Environment configuration completed
  3. beforeRun: Before build starts
  4. run: Begins reading records
  5. beforeCompile: Compilation parameters created
  6. compile: New compilation created
  7. thisCompilation: Compilation initialized
  8. compilation: Compilation completed
  9. make: Module dependency analysis
  10. afterCompile: Compilation ends
  11. emit: Resources generated to directory
  12. afterEmit: Resource writing completed
  13. done: Build ends

Custom Hooks

Plugin developers can create new hooks using tapable:

const { SyncHook } = require('tapable');

class MyPlugin {
  constructor() {
    this.hooks = {
      intercept: new SyncHook(['context'])
    };
  }

  apply(compiler) {
    compiler.hooks.compilation.tap('MyPlugin', (compilation) => {
      this.hooks.intercept.call(compilation);
    });
  }
}

Performance Optimization Tips

Avoid complex calculations in frequently triggered hooks (e.g., seal):

// Use WeakMap to cache calculation results
const cache = new WeakMap();

compilation.hooks.seal.tap('OptimizePlugin', (compilation) => {
  if (!cache.has(compilation)) {
    const result = heavyCalculation(compilation);
    cache.set(compilation, result);
  }
  return cache.get(compilation);
});

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱: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 ☕.