Skip to main content
The Compilation module is created by the Compiler and represents a single build of the assets. In watch mode, a new compilation is created each time a file changes.

Accessing Compilation Hooks

Access compilation hooks through the compiler’s compilation hook:
class MyPlugin {
  apply(compiler) {
    compiler.hooks.compilation.tap('MyPlugin', (compilation) => {
      compilation.hooks.buildModule.tap('MyPlugin', (module) => {
        console.log('Building module');
      });
    });
  }
}

Module Hooks

buildModule

SyncHook<[Module]>
Called before a module is built.
compilation.hooks.buildModule.tap('MyPlugin', (module) => {
  console.log('Building:', module.identifier());
});

rebuildModule

SyncHook<[Module]>
Called when a module is rebuilt in watch mode.
compilation.hooks.rebuildModule.tap('MyPlugin', (module) => {
  console.log('Rebuilding:', module.identifier());
});

succeedModule

SyncHook<[Module]>
Called when a module is successfully built.
compilation.hooks.succeedModule.tap('MyPlugin', (module) => {
  console.log('Successfully built:', module.identifier());
});

failedModule

SyncHook<[Module, WebpackError]>
Called when a module build fails.
compilation.hooks.failedModule.tap('MyPlugin', (module, error) => {
  console.error('Failed to build:', module.identifier(), error);
});

stillValidModule

SyncHook<[Module]>
Called when a module is still valid (cached).
compilation.hooks.stillValidModule.tap('MyPlugin', (module) => {
  console.log('Module still valid:', module.identifier());
});

finishModules

AsyncSeriesHook<[Iterable<Module>]>
Called when all modules have been built.
compilation.hooks.finishModules.tapAsync(
  'MyPlugin',
  (modules, callback) => {
    console.log(`Finished building ${modules.size} modules`);
    callback();
  }
);

finishRebuildingModule

AsyncSeriesHook<[Module]>
Called when a module finishes rebuilding.
compilation.hooks.finishRebuildingModule.tapAsync(
  'MyPlugin',
  (module, callback) => {
    console.log('Finished rebuilding:', module.identifier());
    callback();
  }
);

Entry Hooks

addEntry

SyncHook<[Dependency, EntryOptions]>
Called when an entry is added.
compilation.hooks.addEntry.tap('MyPlugin', (entry, options) => {
  console.log('Adding entry:', options.name);
});

succeedEntry

SyncHook<[Dependency, EntryOptions, Module]>
Called when an entry is successfully processed.
compilation.hooks.succeedEntry.tap(
  'MyPlugin',
  (entry, options, module) => {
    console.log('Entry succeeded:', options.name);
  }
);

failedEntry

SyncHook<[Dependency, EntryOptions, Error]>
Called when an entry fails.
compilation.hooks.failedEntry.tap(
  'MyPlugin',
  (entry, options, error) => {
    console.error('Entry failed:', options.name, error);
  }
);

Sealing Hooks

seal

SyncHook<[]>
Called when compilation sealing begins. After this, no more modules are added.
compilation.hooks.seal.tap('MyPlugin', () => {
  console.log('Compilation sealed');
});

unseal

SyncHook<[]>
Called when compilation is unsealed.
compilation.hooks.unseal.tap('MyPlugin', () => {
  console.log('Compilation unsealed');
});

afterSeal

AsyncSeriesHook<[]>
Called after compilation is sealed.
compilation.hooks.afterSeal.tapAsync('MyPlugin', (callback) => {
  console.log('After seal');
  callback();
});

Chunk Hooks

beforeChunks

SyncHook<[]>
Called before chunk creation.
compilation.hooks.beforeChunks.tap('MyPlugin', () => {
  console.log('Before chunks created');
});

afterChunks

SyncHook<[Iterable<Chunk>]>
Called after chunks are created. Perfect for analyzing the chunk graph.
compilation.hooks.afterChunks.tap('MyPlugin', (chunks) => {
  console.log(`Created ${chunks.size} chunks`);
  for (const chunk of chunks) {
    console.log('Chunk:', chunk.id, 'files:', Array.from(chunk.files));
  }
});

Optimization Hooks

optimize

SyncHook<[]>
Called at the beginning of optimization phase.
compilation.hooks.optimize.tap('MyPlugin', () => {
  console.log('Optimization started');
});

optimizeModules

SyncBailHook<[Iterable<Module>]>
Called during module optimization. Return true to skip remaining optimizations.
compilation.hooks.optimizeModules.tap('MyPlugin', (modules) => {
  for (const module of modules) {
    // Optimize module
  }
});

afterOptimizeModules

SyncHook<[Iterable<Module>]>
Called after module optimization.
compilation.hooks.afterOptimizeModules.tap('MyPlugin', (modules) => {
  console.log('Module optimization complete');
});

optimizeChunks

SyncBailHook<[Iterable<Chunk>, ChunkGroup[]]>
Called during chunk optimization.
compilation.hooks.optimizeChunks.tap(
  'MyPlugin',
  (chunks, chunkGroups) => {
    for (const chunk of chunks) {
      // Optimize chunk
    }
  }
);

afterOptimizeChunks

SyncHook<[Iterable<Chunk>, ChunkGroup[]]>
Called after chunk optimization.
compilation.hooks.afterOptimizeChunks.tap(
  'MyPlugin',
  (chunks, chunkGroups) => {
    console.log('Chunk optimization complete');
  }
);

optimizeTree

AsyncSeriesHook<[Iterable<Chunk>, Iterable<Module>]>
Optimize the dependency tree.
compilation.hooks.optimizeTree.tapAsync(
  'MyPlugin',
  (chunks, modules, callback) => {
    // Optimize module and chunk tree
    callback();
  }
);

optimizeChunkModules

AsyncSeriesBailHook<[Iterable<Chunk>, Iterable<Module>]>
Optimize modules within chunks.
compilation.hooks.optimizeChunkModules.tapAsync(
  'MyPlugin',
  (chunks, modules, callback) => {
    // Optimize how modules are assigned to chunks
    callback();
  }
);

Module & Chunk IDs

moduleIds

SyncHook<[Iterable<Module>]>
Called to assign module IDs.
compilation.hooks.moduleIds.tap('MyPlugin', (modules) => {
  for (const module of modules) {
    if (module.id === null) {
      // Assign custom ID
      module.id = customIdGenerator();
    }
  }
});

chunkIds

SyncHook<[Iterable<Chunk>]>
Called to assign chunk IDs.
compilation.hooks.chunkIds.tap('MyPlugin', (chunks) => {
  for (const chunk of chunks) {
    if (chunk.id === null) {
      // Assign custom ID
      chunk.id = customIdGenerator();
    }
  }
});

Hash Hooks

beforeHash

SyncHook<[]>
Called before hashing.
compilation.hooks.beforeHash.tap('MyPlugin', () => {
  console.log('Before hash generation');
});

afterHash

SyncHook<[]>
Called after compilation is hashed.
compilation.hooks.afterHash.tap('MyPlugin', () => {
  console.log('Hash:', compilation.hash);
});

fullHash

SyncHook<[Hash]>
Called to add custom data to the full hash.
compilation.hooks.fullHash.tap('MyPlugin', (hash) => {
  hash.update('my custom data');
});

chunkHash

SyncHook<[Chunk, Hash, ChunkHashContext]>
Called to add custom data to each chunk’s hash.
compilation.hooks.chunkHash.tap('MyPlugin', (chunk, hash, context) => {
  hash.update('my custom chunk data');
});

contentHash

SyncHook<[Chunk]>
Called to create content hash for a chunk.
compilation.hooks.contentHash.tap('MyPlugin', (chunk) => {
  // Update content hash
});

Asset Hooks

beforeModuleAssets

SyncHook<[]>
Called before module assets are created.
compilation.hooks.beforeModuleAssets.tap('MyPlugin', () => {
  console.log('Creating module assets');
});

beforeChunkAssets

SyncHook<[]>
Called before chunk assets are created.
compilation.hooks.beforeChunkAssets.tap('MyPlugin', () => {
  console.log('Creating chunk assets');
});

processAssets

AsyncSeriesHook<[CompilationAssets]>
The main hook for processing assets. Supports stages for ordering.
const { Compilation } = require('webpack');

compilation.hooks.processAssets.tap(
  {
    name: 'MyPlugin',
    stage: Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE
  },
  (assets) => {
    for (const name in assets) {
      console.log('Processing asset:', name);
      // Modify or analyze asset
    }
  }
);
Asset Processing Stages:
// Add additional assets to compilation
PROCESS_ASSETS_STAGE_ADDITIONAL = -2000

// Basic preprocessing
PROCESS_ASSETS_STAGE_PRE_PROCESS = -1000

// Derive new assets from existing
PROCESS_ASSETS_STAGE_DERIVED = -200

// Add additional sections to existing assets
PROCESS_ASSETS_STAGE_ADDITIONS = -100

// Optimize existing assets
PROCESS_ASSETS_STAGE_OPTIMIZE = 100

// Optimize size of assets
PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE = 400

// Add development tooling
PROCESS_ASSETS_STAGE_DEV_TOOLING = 500

// Optimize asset transfer
PROCESS_ASSETS_STAGE_OPTIMIZE_TRANSFER = 700

// Analyze existing assets
PROCESS_ASSETS_STAGE_ANALYSE = 4000

// Summarize the list of assets
PROCESS_ASSETS_STAGE_SUMMARIZE = Infinity
Example: BannerPlugin (lib/BannerPlugin.js:100):
compilation.hooks.processAssets.tap(
  { 
    name: 'BannerPlugin', 
    stage: Compilation.PROCESS_ASSETS_STAGE_ADDITIONS 
  },
  () => {
    for (const chunk of compilation.chunks) {
      for (const file of chunk.files) {
        compilation.updateAsset(file, (old) => {
          return new ConcatSource(banner, '\n', old);
        });
      }
    }
  }
);

afterProcessAssets

SyncHook<[CompilationAssets]>
Called after asset processing is complete.
compilation.hooks.afterProcessAssets.tap('MyPlugin', (assets) => {
  console.log('Asset processing complete');
});

moduleAsset

SyncHook<[Module, string]>
Called when a module asset is created.
compilation.hooks.moduleAsset.tap('MyPlugin', (module, filename) => {
  console.log('Module asset:', filename);
});

chunkAsset

SyncHook<[Chunk, string]>
Called when a chunk asset is created.
compilation.hooks.chunkAsset.tap('MyPlugin', (chunk, filename) => {
  console.log('Chunk asset:', filename);
});

Record Hooks

record

SyncHook<[Compilation, Records]>
Store information about the compilation.
compilation.hooks.record.tap('MyPlugin', (compilation, records) => {
  records.myPluginData = { /* custom data */ };
});

Stats Hooks

statsPreset

HookMap<SyncHook<[Partial<NormalizedStatsOptions>, CreateStatsOptionsContext]>>
Customize stats presets.
compilation.hooks.statsPreset
  .for('my-preset')
  .tap('MyPlugin', (options, context) => {
    options.assets = true;
    options.modules = true;
  });

statsNormalize

SyncHook<[Partial<NormalizedStatsOptions>, CreateStatsOptionsContext]>
Normalize stats options.
compilation.hooks.statsNormalize.tap('MyPlugin', (options, context) => {
  // Normalize options
});

statsFactory

SyncHook<[StatsFactory, NormalizedStatsOptions]>
Customize how stats are created.
compilation.hooks.statsFactory.tap('MyPlugin', (statsFactory, options) => {
  statsFactory.hooks.extract.tap('MyPlugin', (object, data) => {
    // Extract custom stats
  });
});

statsPrinter

SyncHook<[StatsPrinter, NormalizedStatsOptions]>
Customize how stats are printed.
compilation.hooks.statsPrinter.tap('MyPlugin', (statsPrinter, options) => {
  statsPrinter.hooks.print.tap('MyPlugin', (value, context) => {
    // Custom printing
  });
});

Runtime Requirements Hooks

additionalTreeRuntimeRequirements

SyncHook<[Chunk, RuntimeRequirements, RuntimeRequirementsContext]>
Add runtime requirements for a chunk.
compilation.hooks.additionalTreeRuntimeRequirements.tap(
  'MyPlugin',
  (chunk, runtimeRequirements, context) => {
    runtimeRequirements.add('myCustomRuntime');
  }
);

Complete Example

class MyCompilationPlugin {
  apply(compiler) {
    compiler.hooks.compilation.tap('MyPlugin', (compilation) => {
      // Module building
      compilation.hooks.buildModule.tap('MyPlugin', (module) => {
        console.log('Building:', module.identifier());
      });

      // Optimize modules
      compilation.hooks.optimizeModules.tap('MyPlugin', (modules) => {
        console.log(`Optimizing ${modules.size} modules`);
      });

      // Process assets
      compilation.hooks.processAssets.tap(
        {
          name: 'MyPlugin',
          stage: compilation.PROCESS_ASSETS_STAGE_OPTIMIZE
        },
        (assets) => {
          for (const name in assets) {
            const asset = assets[name];
            console.log(`Asset: ${name}, Size: ${asset.size()}`);
          }
        }
      );

      // After seal
      compilation.hooks.afterSeal.tapAsync('MyPlugin', (callback) => {
        console.log('Compilation sealed');
        callback();
      });
    });
  }
}

See Also