当前位置: 首页 > news >正文

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

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) {
        // 异步处理方式一:callback
        compiler.hooks.emit.tapAsync('AsyncLifecyclePlugin', (compilation, callback) => {
            setTimeout(() => {
                console.log('异步处理完成');
                callback();
            }, 1000);
        });

        // 异步处理方式二:Promise
        compiler.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.dtcms.com/a/74897.html

相关文章:

  • SpringBoot美发门店管理系统开发与设计
  • 网页制作18-Javascipt图像特效の图片闪烁
  • MySQL 横向衍生表(Lateral Derived Tables)
  • element ui设置结束时间为23:59:59
  • VSTO(C#)Excel开发12:多线程的诡异
  • DLMS电能表通讯协议学习笔记
  • 蓝桥杯 第五天 2021 国赛 第 5 题 最小权值
  • Secs/Gem第一讲 · 总结精华版(基于secs4net项目的ChatGpt介绍)
  • 芯谷D6211B:IP摄像头IR滤波器开关驱动的理想选择
  • c++ 中的可变参数模板与折叠表达式
  • 简述下npm,cnpm,yarn和pnpm的区别,以及跟在后面的-g,--save, --save-dev代表着什么
  • 学习网络层
  • python unity通讯数据解析2
  • STAR Decomposition 一种针对极端事件的信号分解方法 论文精读加复现
  • 3.17学习总结
  • 【项目合集】智能语音小车-微信小程序控制
  • WebView2 nuget不能安装到unity项目中
  • 中间件 - 1.nats
  • Matlab GPU加速技术
  • 如何检查CMS建站系统的插件是否安全?
  • 使用 DrissionPage 实现网页内容自动化采集
  • Git Bisect 使用指南:高效定位引入 Bug 的提交
  • Qt之自定义界面组件 一
  • Jenkins 快讯
  • STM32G070CBT6读写FLASH中的数据
  • 浅谈Mysql数据库事务操作 用mybatis操作mysql事务 再在Springboot中使用Spring事务控制mysql事务回滚
  • ‌RTSPtoWeb, 一个将rtsp转换成webrtc的开源项目
  • 银河麒麟V10SP3Server中离线安装Docker引擎与docker-compose
  • 电池预测 | 第23讲 基于CNN-BiLSTM的锂电池剩余寿命预测,附带PPT视频讲解
  • GB9706.1-2020附件J绝缘路径参考