详细讲一下 Webpack 主要生命周期钩子流程(重难点)

devtools/2025/3/19 1:51:06/

1. Webpack 主要生命周期钩子流程

class LifecyclePlugin {apply(compiler) {// 1. 初始化阶段compiler.hooks.initialize.tap('LifecyclePlugin', () => {console.log('1. 初始化 Webpack');});// 2. 开始编译compiler.hooks.beforeRun.tap('LifecyclePlugin', () => {console.log('2. 编译开始前');});// 3. compilation 对象创建compiler.hooks.compilation.tap('LifecyclePlugin', (compilation) => {console.log('3. compilation 对象创建完成');// compilation 的子生命周期compilation.hooks.buildModule.tap('LifecyclePlugin', () => {console.log('3.1 模块构建开始');});compilation.hooks.finishModules.tap('LifecyclePlugin', () => {console.log('3.2 所有模块构建完成');});});// 4. 生成资源compiler.hooks.emit.tap('LifecyclePlugin', () => {console.log('4. 生成资源到 output 目录之前');});// 5. 完成编译compiler.hooks.done.tap('LifecyclePlugin', () => {console.log('5. 编译完成');});}
}

2. 主要生命周期阶段及其作用

class ExamplePlugin {apply(compiler) {// 1. 配置阶段compiler.hooks.entryOption.tap('ExamplePlugin', (context, entry) => {// 入口文件配置完成后触发// 适合做入口文件的检查或修改});// 2. 编译阶段compiler.hooks.compilation.tap('ExamplePlugin', (compilation) => {// 一次新的编译创建完成后触发// 适合处理模块相关的事务compilation.hooks.optimizeModules.tap('ExamplePlugin', (modules) => {// 模块优化阶段// 可以对模块进行优化处理});});// 3. 输出阶段compiler.hooks.emit.tapAsync('ExamplePlugin', (compilation, callback) => {// 资源输出到目录之前触发// 适合修改最终的资源内容const manifest = {};for (const name of Object.keys(compilation.assets)) {manifest[name] = compilation.assets[name].size();}callback();});}
}

3. 实际应用示例

class FileListPlugin {apply(compiler) {// compilation 阶段:收集模块信息compiler.hooks.compilation.tap('FileListPlugin', (compilation) => {const fileList = [];// 监听模块构建compilation.hooks.buildModule.tap('FileListPlugin', (module) => {if (module.resource) {fileList.push(module.resource);}});// emit 阶段:生成文件清单compiler.hooks.emit.tapAsync('FileListPlugin', (compilation, callback) => {// 创建文件清单const content = fileList.join('\n');compilation.assets['filelist.txt'] = {source: () => content,size: () => content.length};callback();});});}
}

4. 常见生命周期钩子的使用场景

class CommonUsagePlugin {apply(compiler) {// 1. 用于环境检查compiler.hooks.initialize.tap('CommonUsagePlugin', () => {if (process.env.NODE_ENV !== 'production') {console.warn('当前为开发环境');}});// 2. 用于资源统计compiler.hooks.compilation.tap('CommonUsagePlugin', (compilation) => {let totalSize = 0;compilation.hooks.chunkAsset.tap('CommonUsagePlugin', (chunk, filename) => {const asset = compilation.assets[filename];totalSize += asset.size();});});// 3. 用于性能分析let startTime;compiler.hooks.run.tap('CommonUsagePlugin', () => {startTime = Date.now();});compiler.hooks.done.tap('CommonUsagePlugin', () => {const endTime = Date.now();console.log(`编译耗时: ${endTime - startTime}ms`);});}
}

5. 异步生命周期的处理

class AsyncLifecyclePlugin {apply(compiler) {// 异步处理方式一:callbackcompiler.hooks.emit.tapAsync('AsyncLifecyclePlugin', (compilation, callback) => {setTimeout(() => {console.log('异步处理完成');callback();}, 1000);});// 异步处理方式二:Promisecompiler.hooks.emit.tapPromise('AsyncLifecyclePlugin', (compilation) => {return new Promise((resolve) => {setTimeout(() => {console.log('Promise异步处理完成');resolve();}, 1000);});});}
}

6. 生命周期钩子的执行顺序

// Webpack 编译流程的主要步骤:
1. entry-option    -> 初始化选项
2. run            -> 开始编译
3. make           -> 从入口开始递归分析依赖,对每个依赖模块进行构建
4. build-module   -> 构建模块
5. normal-module  -> 普通模块构建
6. loader         -> 加载器加载模块
7. program        -> 解析AST
8. seal           -> 封装构建结果
9. emit           -> 把各个chunk输出到结果文件
10. done          -> 完成编译

这些生命周期钩子的优点是:

  1. 可以在特定的时机介入编译过程
  2. 提供了灵活的异步处理能力
  3. 可以访问和修改编译过程中的数据
  4. 便于插件之间的解耦和组合

使用这些生命周期钩子时需要注意:

  • 选择合适的钩子时机
  • 正确处理异步操作
  • 注意不同钩子之间的依赖关系
  • 避免在不必要的钩子中执行耗时操作

http://www.ppmy.cn/devtools/168208.html

相关文章

【后端】【django】抛弃 Django 自带用户管理后,能否使用 `simple-jwt`?

抛弃 Django 自带用户管理后,能否使用 simple-jwt? 一、结论 是的,即使抛弃了 Django 自带的用户管理(AbstractUser 或 AbstractBaseUser),仍然可以使用 django-rest-framework-simplejwt(简称…

Java中接口隔离原则简介和代码举例

简介: 接口隔离原则(Interface Segregation Principle,ISP)是面向对象设计SOLID原则中的“I”,其核心思想是: 定义 客户端不应被迫依赖它不使用的方法。即,一个类对另一个类的依赖应建立在最…

软考中级-数据库-4.4 文件管理与作业管理

主要考点 文件管理: 1、文件的结构和组织 2、文件的目录结构 3、文件存储空间的管理 4、作业调度算法 文件的结构和组织 • 文件的逻辑结构:从用户角度看到的文件组织形式就是文件的逻辑结构,但实际上这些文件在内存上的存放方式可能并不是这…

Hyperlane:轻量、高效、安全的 Rust Web 框架新选择

Hyperlane:轻量、高效、安全的 Rust Web 框架新选择 在 Web 开发的世界中,框架的选择往往决定了项目的效率与未来。Hyperlane,一款基于 Rust 语言打造的轻量级 Web 框架,正以其卓越的性能、简洁的设计和可靠的安全性,…

WEB安全--SQL注入--DNSlog外带

一、原理: 访问域名时,dns协议将我们访问的语句解析为ip地址,并将其记录在其日志中;在这个过程中,如果我们在语句中写入SQL注入的语句,那么在dns解析时会执行这些语句并通过concat将结果和域名一起记录在日…

动作捕捉手套如何让虚拟现实人机交互 “触手可及”?

在虚拟与现实逐渐交融的当下,动作捕捉技术正以前所未有的速度革新着多个领域。 动作捕捉技术,简称“动捕”,已经从早期的影视特效制作,逐步拓展到游戏开发、虚拟现实、机器人控制等多个领域。 而mHandPrO数据手套作为这一领域的…

汉桑科技IPO:潜藏两大风险 公众投资者权益或受损

冰山之所以危险,是因为只有八分之一在水面上。 ——语出小说家海明威。 引 言 野村证券提供的一份报告显示,2025年前两个月,我国出口同比增长仅有2.3%,与去年四季度9.9%的增长显著下滑。与此同时,从2月1日开始&a…

技术栈分享之----Swagger

一:swagger介绍 相信无论是前端还是后端开发,都或多或少地被接口文档折磨过。前端经常抱怨后端给的接口文档与实际情况不一致。后端又觉得编写及维护接口文档会耗费不少精力,经常来不及更新。其实无论是前端调用后端,还是后端调用…