Webpack 的 Compiler 与 Compilation
在 Webpack 的构建过程中,Compiler 和 Compilation 是两个最核心的概念,它们分别代表了编译器实例和单次编译过程。
Compiler 概述
Compiler 是 Webpack 的主环境对象,它包含了所有的配置信息,包括 options、loaders、plugins 等。在 Webpack 启动时会实例化一个 Compiler 对象,该对象在整个 Webpack 生命周期中都存在,只会被创建一次。
Compiler 核心特性
// Compiler 类的基本结构
class Compiler extends Tapable {
constructor(context) {
super();
this.hooks = {
// 环境准备钩子
environment: new SyncHook([]),
afterEnvironment: new SyncHook([]),
entryOption: new SyncBailHook(['context', 'entry']),
afterPlugins: new SyncHook(['compiler']),
afterResolvers: new SyncHook(['compiler']),
// 编译生命周期钩子
beforeRun: new AsyncSeriesHook(['compiler']),
run: new AsyncSeriesHook(['compiler']),
beforeCompile: new AsyncSeriesHook(['params']),
compile: new SyncHook(['params']),
thisCompilation: new SyncHook(['compilation', 'params']),
compilation: new SyncHook(['compilation', 'params']),
make: new AsyncParallelHook(['compilation']),
afterCompile: new AsyncSeriesHook(['compilation']),
// 输出阶段钩子
shouldEmit: new SyncBailHook(['compilation']),
emit: new AsyncSeriesHook(['compilation']),
afterEmit: new AsyncSeriesHook(['compilation']),
assetEmitted: new AsyncSeriesHook(['file', 'content']),
// 完成和错误处理钩子
done: new AsyncSeriesHook(['stats']),
failed: new SyncHook(['error']),
// 监听模式钩子
watchRun: new AsyncSeriesHook(['compiler']),
watchClose: new SyncHook([]),
invalid: new SyncHook(['filename', 'changeTime'])
};
// 编译器状态
this.context = context;
this.running = false;
this.watchMode = false;
this.outputPath = '';
this.outputFileSystem = null;
this.inputFileSystem = null;
// 配置信息
this.options = {};
this.resolverFactory = new ResolverFactory();
this.fileTimestamps = new Map();
this.contextTimestamps = new Map();
// 编译记录
this.records = {};
this.removedFiles = new Set();
this.modifiedFiles = new Set();
// 插件和解析器
this.resolvers = {
normal: null,
context: null,
loader: null
};
}
// 运行编译
run(callback) {
if (this.running) {
return callback(new Error('Compiler is already running'));
}
this.running = true;
const finalCallback = (err, stats) => {
this.running = false;
if (callback) callback(err, stats);
};
// 执行编译前钩子
this.hooks.beforeRun.callAsync(this, (err) => {
if (err) return finalCallback(err);
this.hooks.run.callAsync(this, (err) => {
if (err) return finalCallback(err);
// 开始编译
this.compile((err, compilation) => {
if (err) return finalCallback(err);
// 输出文件
this.emitAssets(compilation, (err) => {
if (err) return finalCallback(err);
// 编译完成
const stats = new Stats(compilation);
this.hooks.done.callAsync(stats, (err) => {
if (err) return finalCallback(err);
return finalCallback(null, stats);
});
});
});
});
});
}
// 监听模式
watch(watchOptions, handler) {
if (this.running) {
return handler(new Error('Compiler is already running'));
}
this.running = true;
this.watchMode = true;
return new Watching(this, watchOptions, handler);
}
// 创建编译实例
compile(callback) {
const params = this.newCompilationParams();
this.hooks.beforeCompile.callAsync(params, (err) => {
if (err) return callback(err);
this.hooks.compile.call(params);
const compilation = this.newCompilation(params);
this.hooks.make.callAsync(compilation, (err) => {
if (err) return callback(err);
compilation.finish((err) => {
if (err) return callback(err);
compilation.seal((err) => {
if (err) return callback(err);
this.hooks.afterCompile.callAsync(compilation, (err) => {
if (err) return callback(err);
return callback(null, compilation);
});
});
});
});
});
}
// 创建新的编译参数
newCompilationParams() {
const params = {
normalModuleFactory: new NormalModuleFactory({
context: this.options.context,
fs: this.inputFileSystem,
resolverFactory: this.resolverFactory
}),
contextModuleFactory: new ContextModuleFactory(this.resolverFactory)
};
return params;
}
// 创建新的编译实例
newCompilation(params) {
const compilation = new Compilation(this);
compilation.fileTimestamps = this.fileTimestamps;
compilation.contextTimestamps = this.contextTimestamps;
compilation.name = this.name;
compilation.records = this.records;
compilation.compilationDependencies = params.compilationDependencies;
this.hooks.thisCompilation.call(compilation, params);
this.hooks.compilation.call(compilation, params);
return compilation;
}
// 输出资源
emitAssets(compilation, callback) {
let outputPath;
const emitFiles = (err) => {
if (err) return callback(err);
const assets = compilation.getAssets();
// 异步输出所有资源
asyncLib.forEachLimit(
assets,
15,
(asset, callback) => {
let targetFile = asset.name;
let targetPath = this.outputPath;
const queryStringIdx = targetFile.indexOf('?');
if (queryStringIdx >= 0) {
targetFile = targetFile.substr(0, queryStringIdx);
}
const writeOut = (err) => {
if (err) return callback(err);
const targetPath = this.outputPath + '/' + targetFile;
const source = asset.source();
// 触发资源输出钩子
this.hooks.assetEmitted.callAsync(targetFile, source, callback);
};
if (asset.existsAt === targetPath) {
return callback();
}
// 写入文件
this.outputFileSystem.writeFile(
this.outputPath + '/' + targetFile,
asset.source(),
writeOut
);
},
(err) => {
if (err) return callback(err);
this.hooks.afterEmit.callAsync(compilation, callback);
}
);
};
this.hooks.emit.callAsync(compilation, emitFiles);
}
}
Compiler 生命周期
Compilation 概述
Compilation 代表了一次单独的编译过程,包含了当前的模块资源、编译生成的资源、变化的文件等信息。每次文件变化都会创建一个新的 Compilation 实例。
Compilation 核心特性
// Compilation 类的基本结构
class Compilation extends Tapable {
constructor(compiler) {
super();
this.compiler = compiler;
this.hooks = {
// 构建阶段钩子
buildModule: new SyncHook(['module']),
rebuildModule: new SyncHook(['module']),
failedModule: new SyncHook(['module', 'error']),
succeedModule: new SyncHook(['module']),
finishModules: new AsyncSeriesHook(['modules']),
finishRebuildingModule: new SyncHook(['module']),
// 依赖处理钩子
addEntry: new SyncHook(['entry', 'name']),
failedEntry: new SyncHook(['entry', 'name', 'error']),
succeedEntry: new SyncHook(['entry', 'name', 'module']),
// 封装阶段钩子
seal: new SyncHook([]),
unseal: new SyncHook([]),
beforeChunks: new SyncHook([]),
afterChunks: new SyncHook(['chunks']),
// 优化阶段钩子
optimize: new SyncHook([]),
optimizeModules: new SyncBailHook(['modules']),
afterOptimizeModules: new SyncHook(['modules']),
optimizeChunks: new SyncBailHook(['chunks', 'chunkGroups']),
afterOptimizeChunks: new SyncHook(['chunks', 'chunkGroups']),
optimizeTree: new AsyncSeriesHook(['chunks', 'modules']),
afterOptimizeTree: new SyncHook(['chunks', 'modules']),
// 模块和chunk ID优化
beforeModuleIds: new SyncHook(['modules']),
moduleIds: new SyncHook(['modules']),
optimizeModuleIds: new SyncHook(['modules']),
afterOptimizeModuleIds: new SyncHook(['modules']),
beforeChunkIds: new SyncHook(['chunks']),
optimizeChunkIds: new SyncHook(['chunks']),
afterOptimizeChunkIds: new SyncHook(['chunks']),
// 代码生成钩子
beforeCodeGeneration: new SyncHook([]),
afterCodeGeneration: new SyncHook([]),
// 资源处理钩子
beforeModuleAssets: new SyncHook([]),
additionalChunkAssets: new SyncHook(['chunks']),
additionalAssets: new AsyncSeriesHook([]),
optimizeChunkAssets: new AsyncSeriesHook(['chunks']),
afterOptimizeChunkAssets: new SyncHook(['chunks']),
optimizeAssets: new AsyncSeriesHook(['assets']),
afterOptimizeAssets: new SyncHook(['assets']),
// 记录和哈希
beforeHash: new SyncHook([]),
afterHash: new SyncHook([]),
recordHash: new SyncHook(['records']),
record: new SyncHook(['compilation', 'records']),
beforeModuleAssets: new SyncHook([]),
additionalChunkAssets: new SyncHook(['chunks']),
shouldGenerateChunkAssets: new SyncBailHook([]),
beforeChunkAssets: new SyncHook([]),
// 统计信息
statsFactory: new SyncHook(['statsFactory', 'options']),
statsPrinter: new SyncHook(['statsPrinter', 'options'])
};
// 编译状态
this.name = undefined;
this.needAdditionalPass = false;
this.startTime = undefined;
this.endTime = undefined;
// 模块和依赖
this.modules = new Set();
this.chunks = new Set();
this.chunkGroups = [];
this.namedChunkGroups = new Map();
this.namedChunks = new Map();
this.moduleGraph = new ModuleGraph();
this.chunkGraph = new ChunkGraph(this.moduleGraph);
this.codeGenerationResults = new Map();
// 入口点
this.entries = new Map();
this.entrypoints = new Map();
this.asyncEntrypoints = [];
// 资源
this.assets = {};
this.assetsInfo = new Map();
// 缓存和文件系统
this.cache = compiler.cache;
this.fileSystemInfo = new FileSystemInfo(compiler.inputFileSystem);
// 错误和警告
this.errors = [];
this.warnings = [];
this.children = [];
// 依赖关系
this.fileDependencies = new Set();
this.contextDependencies = new Set();
this.missingDependencies = new Set();
this.buildDependencies = new Set();
}
// 添加入口模块
addEntry(context, entry, optionsOrName, callback) {
const options = typeof optionsOrName === 'object'
? optionsOrName
: { name: optionsOrName };
this.hooks.addEntry.call(entry, options.name);
this._addEntryItem(context, entry, 'main', options, (err, module) => {
if (err) {
this.hooks.failedEntry.call(entry, options.name, err);
return callback(err);
}
this.hooks.succeedEntry.call(entry, options.name, module);
return callback(null, module);
});
}
// 构建模块
buildModule(module, callback) {
this.hooks.buildModule.call(module);
module.build(
this.options,
this,
this.resolverFactory.get('normal', module.resolveOptions),
this.inputFileSystem,
(err) => {
if (err) {
this.hooks.failedModule.call(module, err);
return callback(err);
}
this.hooks.succeedModule.call(module);
return callback();
}
);
}
// 处理模块依赖
processModuleDependencies(module, callback) {
const dependencies = new Map();
// 收集所有依赖
const addDependency = (dep) => {
const resourceIdent = dep.getResourceIdentifier();
if (resourceIdent) {
const factory = this.dependencyFactories.get(dep.constructor);
if (factory) {
dependencies.set(resourceIdent, {
factory,
dependencies: dependencies.get(resourceIdent) || [],
dependency: dep
});
dependencies.get(resourceIdent).dependencies.push(dep);
}
}
};
// 遍历模块的所有依赖
for (const dependency of module.dependencies) {
addDependency(dependency);
}
// 异步处理所有依赖
asyncLib.forEach(
Array.from(dependencies.values()),
(item, callback) => {
this._handleModuleDependency(module, item, callback);
},
callback
);
}
// 封装编译结果
seal(callback) {
this.hooks.seal.call();
// 完成模块构建
this.hooks.finishModules.callAsync(this.modules, (err) => {
if (err) return callback(err);
// 创建chunk图
this._createChunkGraph();
// 优化
this._optimize();
// 代码生成
this._codeGeneration((err) => {
if (err) return callback(err);
// 创建哈希
this._createHash();
// 生成资源
this._createModuleAssets();
this._createChunkAssets();
callback();
});
});
}
// 创建chunk图
_createChunkGraph() {
this.hooks.beforeChunks.call();
// 为每个入口创建chunk
for (const [name, entrypoint] of this.entrypoints) {
const chunk = new Chunk(name);
chunk.entryModule = entrypoint.getRuntimeChunk();
this.chunks.add(chunk);
this.namedChunks.set(name, chunk);
}
this.hooks.afterChunks.call(this.chunks);
}
// 优化过程
_optimize() {
this.hooks.optimize.call();
// 优化模块
while (this.hooks.optimizeModules.call(this.modules)) {
// 重复执行直到没有更多优化
}
this.hooks.afterOptimizeModules.call(this.modules);
// 优化chunks
while (this.hooks.optimizeChunks.call(this.chunks, this.chunkGroups)) {
// 重复执行直到没有更多优化
}
this.hooks.afterOptimizeChunks.call(this.chunks, this.chunkGroups);
// 优化依赖树
this.hooks.optimizeTree.callAsync(this.chunks, this.modules, (err) => {
if (err) return;
this.hooks.afterOptimizeTree.call(this.chunks, this.modules);
});
// 优化模块ID
this.hooks.beforeModuleIds.call(this.modules);
this.hooks.moduleIds.call(this.modules);
this.hooks.optimizeModuleIds.call(this.modules);
this.hooks.afterOptimizeModuleIds.call(this.modules);
// 优化chunk ID
this.hooks.beforeChunkIds.call(this.chunks);
this.hooks.optimizeChunkIds.call(this.chunks);
this.hooks.afterOptimizeChunkIds.call(this.chunks);
}
// 代码生成
_codeGeneration(callback) {
this.hooks.beforeCodeGeneration.call();
const jobs = [];
for (const module of this.modules) {
for (const runtime of this.chunkGraph.getModuleRuntimes(module)) {
jobs.push({ module, runtime });
}
}
asyncLib.eachLimit(
jobs,
100,
({ module, runtime }, callback) => {
this._codeGenerationModule(module, runtime, callback);
},
(err) => {
if (err) return callback(err);
this.hooks.afterCodeGeneration.call();
callback();
}
);
}
// 为单个模块生成代码
_codeGenerationModule(module, runtime, callback) {
const codeGenerationResult = module.codeGeneration({
dependencyTemplates: this.dependencyTemplates,
runtimeTemplate: this.runtimeTemplate,
moduleGraph: this.moduleGraph,
chunkGraph: this.chunkGraph,
runtime: runtime
});
this.codeGenerationResults.set(module, codeGenerationResult);
callback();
}
// 创建模块资源
_createModuleAssets() {
this.hooks.beforeModuleAssets.call();
for (const module of this.modules) {
if (module.buildInfo.assets) {
for (const assetName of Object.keys(module.buildInfo.assets)) {
const fileName = this.getPath(assetName, {
module
});
this.assets[fileName] = module.buildInfo.assets[assetName];
this.assetsInfo.set(fileName, {
sourceFilename: module.resource
});
}
}
}
}
// 创建chunk资源
_createChunkAssets() {
for (const chunk of this.chunks) {
const manifest = this.getRenderManifest({
chunk,
hash: this.hash,
fullHash: this.fullHash,
outputOptions: this.outputOptions,
moduleTemplates: this.moduleTemplates,
dependencyTemplates: this.dependencyTemplates
});
for (const fileManifest of manifest) {
const fileName = fileManifest.pathOptions
? this.getPath(fileManifest.filename, fileManifest.pathOptions)
: fileManifest.filename;
this.assets[fileName] = fileManifest.render();
this.assetsInfo.set(fileName, {
chunk,
contenthash: fileManifest.hash
});
chunk.files.add(fileName);
}
}
}
// 创建哈希
_createHash() {
this.hooks.beforeHash.call();
const hash = createHash(this.outputOptions.hashFunction);
// 为每个chunk计算哈希
for (const chunk of this.chunks) {
const chunkHash = createHash(this.outputOptions.hashFunction);
for (const module of this.chunkGraph.getOrderedChunkModules(chunk)) {
chunkHash.update(module.hash);
}
chunk.hash = chunkHash.digest('hex');
hash.update(chunk.hash);
}
this.hash = hash.digest('hex');
this.fullHash = this.hash;
this.hooks.afterHash.call();
}
// 获取统计信息
getStats() {
return new Stats(this);
}
// 获取所有资源
getAssets() {
const array = [];
for (const assetName of Object.keys(this.assets)) {
if (Object.prototype.hasOwnProperty.call(this.assets, assetName)) {
array.push({
name: assetName,
source: this.assets[assetName],
info: this.assetsInfo.get(assetName) || {}
});
}
}
return array;
}
}
Compilation 生命周期
通过深入分析 Compilation 的构建过程,我们可以更好地理解 Webpack 的工作机制,并为性能优化和插件开发提供指导。
Compiler 与 Compilation 的关系
核心关系分析
Compiler 和 Compilation 之间存在明确的层次关系和职责划分:
// Compiler 和 Compilation 关系示例
class CompilerCompilationRelationship {
constructor() {
this.compiler = null;
this.currentCompilation = null;
}
// 演示 Compiler 如何管理 Compilation
demonstrateRelationship() {
// 1. Compiler 是单例,整个构建过程只有一个
this.compiler = new Compiler('/project/root');
// 2. Compiler 负责创建 Compilation 实例
const compilation1 = this.compiler.newCompilation();
console.log('第一次编译:', compilation1.name);
// 3. 在监听模式下,文件变化会创建新的 Compilation
const compilation2 = this.compiler.newCompilation();
console.log('第二次编译:', compilation2.name);
// 4. 每个 Compilation 都有对 Compiler 的引用
console.log('Compilation 的 Compiler 引用:', compilation1.compiler === this.compiler);
}
// Compiler 和 Compilation 的数据流
dataFlowExample() {
const compiler = new Compiler('/project');
// Compiler 的配置传递给 Compilation
compiler.options = {
entry: './src/index.js',
output: {
path: '/dist',
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader'
}
]
}
};
// 创建 Compilation 时传递必要信息
const compilation = compiler.newCompilation({
normalModuleFactory: new NormalModuleFactory(compiler.options),
contextModuleFactory: new ContextModuleFactory()
});
// Compilation 使用 Compiler 的配置和资源
compilation.outputOptions = compiler.options.output;
compilation.resolverFactory = compiler.resolverFactory;
compilation.inputFileSystem = compiler.inputFileSystem;
compilation.outputFileSystem = compiler.outputFileSystem;
return { compiler, compilation };
}
}
生命周期同步机制
// Compiler 和 Compilation 生命周期同步
class LifecycleSynchronization {
constructor() {
this.compiler = new Compiler();
this.setupLifecycleSync();
}
setupLifecycleSync() {
// Compiler 创建 Compilation 时的钩子同步
this.compiler.hooks.thisCompilation.tap('LifecycleSync', (compilation, params) => {
console.log('Compiler 创建了新的 Compilation');
// 在 Compilation 的各个阶段添加监听
compilation.hooks.buildModule.tap('CompilerSync', (module) => {
console.log(`Compiler 监听到模块构建: ${module.resource}`);
});
compilation.hooks.seal.tap('CompilerSync', () => {
console.log('Compiler 监听到 Compilation 开始封装');
});
compilation.hooks.optimizeChunks.tap('CompilerSync', (chunks) => {
console.log(`Compiler 监听到代码块优化: ${chunks.size} 个代码块`);
});
});
// Compilation 完成后的处理
this.compiler.hooks.afterCompile.tapAsync('LifecycleSync', (compilation, callback) => {
console.log('Compilation 完成,Compiler 开始后续处理');
// Compiler 可以访问 Compilation 的结果
const stats = {
modules: compilation.modules.size,
chunks: compilation.chunks.size,
assets: Object.keys(compilation.assets).length,
errors: compilation.errors.length,
warnings: compilation.warnings.length
};
console.log('编译统计:', stats);
callback();
});
}
// 演示数据传递
demonstrateDataPassing() {
const compiler = this.compiler;
compiler.run((err, stats) => {
if (err) {
console.error('编译失败:', err);
return;
}
// stats 包含了 Compilation 的所有信息
console.log('编译成功:', {
hash: stats.hash,
version: stats.version,
time: stats.endTime - stats.startTime,
assets: stats.assets.length,
chunks: stats.chunks.length,
modules: stats.modules.length,
errors: stats.errors.length,
warnings: stats.warnings.length
});
});
}
}
实践应用与优化
性能监控插件
// 基于 Compiler 和 Compilation 的性能监控插件
class PerformanceMonitorPlugin {
constructor(options = {}) {
this.options = {
outputFile: 'build-performance.json',
threshold: {
buildTime: 5000, // 构建时间阈值(ms)
moduleCount: 1000, // 模块数量阈值
chunkCount: 50, // chunk数量阈值
assetSize: 1024 * 1024 // 资源大小阈值(bytes)
},
...options
};
this.metrics = {
compiler: {},
compilations: []
};
}
apply(compiler) {
const pluginName = PerformanceMonitorPlugin.name;
// 监控 Compiler 生命周期
this.setupCompilerMonitoring(compiler, pluginName);
// 监控 Compilation 生命周期
compiler.hooks.thisCompilation.tap(pluginName, (compilation) => {
this.setupCompilationMonitoring(compilation, pluginName);
});
// 输出性能报告
compiler.hooks.done.tap(pluginName, (stats) => {
this.generatePerformanceReport(stats);
});
}
setupCompilerMonitoring(compiler, pluginName) {
let compilerStartTime;
// Compiler 启动
compiler.hooks.beforeRun.tap(pluginName, () => {
compilerStartTime = Date.now();
this.metrics.compiler.startTime = compilerStartTime;
console.log('🚀 编译器启动');
});
// 编译完成
compiler.hooks.done.tap(pluginName, (stats) => {
const endTime = Date.now();
const duration = endTime - compilerStartTime;
this.metrics.compiler.endTime = endTime;
this.metrics.compiler.duration = duration;
this.metrics.compiler.totalCompilations = this.metrics.compilations.length;
console.log(`✅ 编译完成,总耗时: ${duration}ms`);
// 检查性能阈值
this.checkPerformanceThresholds(stats, duration);
});
}
setupCompilationMonitoring(compilation, pluginName) {
const compilationMetrics = {
startTime: Date.now(),
modules: { total: 0, built: 0, cached: 0, failed: 0 },
chunks: { total: 0, initial: 0, async: 0 },
assets: { total: 0, size: 0 },
phases: {}
};
// 模块构建监控
compilation.hooks.buildModule.tap(pluginName, (module) => {
compilationMetrics.modules.total++;
if (!compilationMetrics.phases.moduleBuilding) {
compilationMetrics.phases.moduleBuilding = Date.now();
}
});
compilation.hooks.succeedModule.tap(pluginName, (module) => {
if (module.built) {
compilationMetrics.modules.built++;
} else {
compilationMetrics.modules.cached++;
}
});
// 封装阶段监控
compilation.hooks.seal.tap(pluginName, () => {
compilationMetrics.phases.seal = Date.now();
console.log('🔒 开始封装阶段');
});
// Chunk 创建监控
compilation.hooks.afterChunks.tap(pluginName, (chunks) => {
compilationMetrics.phases.chunksCreated = Date.now();
compilationMetrics.chunks.total = chunks.size;
let initialChunks = 0;
let asyncChunks = 0;
for (const chunk of chunks) {
if (chunk.isOnlyInitial()) {
initialChunks++;
} else {
asyncChunks++;
}
}
compilationMetrics.chunks.initial = initialChunks;
compilationMetrics.chunks.async = asyncChunks;
console.log(`📋 Chunk 创建完成: ${chunks.size} 个`);
});
// 记录完成时间
compilation.hooks.statsFactory.tap(pluginName, () => {
compilationMetrics.endTime = Date.now();
compilationMetrics.duration = compilationMetrics.endTime - compilationMetrics.startTime;
this.metrics.compilations.push(compilationMetrics);
console.log(`🏁 Compilation 完成,耗时: ${compilationMetrics.duration}ms`);
});
}
checkPerformanceThresholds(stats, duration) {
const warnings = [];
const { threshold } = this.options;
// 检查构建时间
if (duration > threshold.buildTime) {
warnings.push(`构建时间过长: ${duration}ms (阈值: ${threshold.buildTime}ms)`);
}
// 检查模块数量
if (stats.compilation.modules.size > threshold.moduleCount) {
warnings.push(`模块数量过多: ${stats.compilation.modules.size} (阈值: ${threshold.moduleCount})`);
}
// 输出警告
if (warnings.length > 0) {
console.log('\n⚠️ 性能警告:');
warnings.forEach(warning => console.log(` ${warning}`));
}
return warnings;
}
generatePerformanceReport(stats) {
const report = {
timestamp: new Date().toISOString(),
compiler: this.metrics.compiler,
compilations: this.metrics.compilations,
summary: this.generateSummary(stats)
};
// 输出到文件
const reportJson = JSON.stringify(report, null, 2);
stats.compilation.assets[this.options.outputFile] = {
source: () => reportJson,
size: () => reportJson.length
};
console.log(`\n📊 性能报告已生成: ${this.options.outputFile}`);
}
generateSummary(stats) {
const lastCompilation = this.metrics.compilations[this.metrics.compilations.length - 1];
return {
totalDuration: this.metrics.compiler.duration,
compilationCount: this.metrics.compilations.length,
modules: {
total: stats.compilation.modules.size,
built: lastCompilation?.modules.built || 0,
cached: lastCompilation?.modules.cached || 0
},
chunks: {
total: stats.compilation.chunks.size,
initial: lastCompilation?.chunks.initial || 0,
async: lastCompilation?.chunks.async || 0
},
assets: {
count: Object.keys(stats.compilation.assets).length,
size: lastCompilation?.assets.size || 0
}
};
}
}
总结
通过深入分析 Webpack 的 Compiler 和 Compilation,我们可以得出以下关键认识:
核心差异
- 生命周期:Compiler 贯穿整个 Webpack 运行周期,而 Compilation 代表单次编译过程
- 职责分工:Compiler 负责环境搭建和流程控制,Compilation 负责具体的编译工作
- 数据管理:Compiler 管理全局配置和状态,Compilation 管理编译过程中的模块和资源
架构优势
- 职责分离:清晰的职责划分使得代码更容易维护和扩展
- 插件友好:丰富的钩子系统为插件开发提供了强大的扩展能力
- 性能优化:通过缓存和增量编译机制提升构建性能
实践建议
- 插件开发:根据需求选择合适的钩子,理解 Compiler 和 Compilation 的不同阶段
- 性能优化:利用缓存机制和并行处理提升构建效率
- 监控分析:通过性能监控插件了解构建瓶颈,持续优化构建流程
理解 Compiler 和 Compilation 的工作原理,对于前端架构师来说是必备技能,它不仅有助于我们更好地使用 Webpack,还能让我们在遇到构建问题时快速定位和解决问题。