《Webpack5 核心原理与应用实践》学习笔记-> 提升插件健壮性

简介: 《Webpack5 核心原理与应用实践》学习笔记-> 提升插件健壮性

其实从loader开始,个人已经没有多少想法了,自己基本上用不到loaderplugin的开发, 目前的情况也不需要开发或者是调试这些玩意,而且课程里面干货嗯,所以差点弃坑,但是反正就剩几章了,咬咬牙吧,这是写给自己的,后面把一个技术栈弄得七七八八了再来写专栏。


插件的健壮性其实和自己写的项目类似,要排查问题,需要记录日志,分析性能瓶颈等,这些webpack都替你考虑过了, 所以会有一些工具来帮助你做这些事。


日志处理


在之前的loader中写过,可以通过this.getLogger()来使用日志功能,它是内置了infrastructureLogging,还不了解可以翻翻之前写的或者去webpack官网搜索一下这个。


loader中使用是通过注入的上下文this来获取log,在plugin中是通过apply中传入的compiler或者compilation来使用的,如下:


class MyPlugin {
    apply(compiler) {
        // 通过compiler.getInfrastructureLogger获取一个logger
        const logger = compiler.getInfrastructureLogger('MyPlugin');
        logger.info('MyPlugin is starting');
        compiler.hooks.emit.tapAsync('MyPlugin', (compilation, callback) => {
            // 通过compilation.getLogger获取一个logger
            const logger = compilation.getLogger('MyPlugin');
            logger.info('Hello from MyPlugin');
            callback();
        })
    }
}
module.exports = MyPlugin;

log的日志分级就不用讲了吧,接下来就是通过log上报异常,通过log上报的异常不会中断webpack的构建:


class MyPlugin {
    apply(compiler) {
        compiler.hooks.emit.tapAsync('MyPlugin', (compilation, callback) => {
            // 通过compilation.getLogger获取一个logger
            const logger = compilation.getLogger('MyPlugin');
            // log的分级
            logger.info('Hello from MyPlugin');
            logger.log('Log from MyPlugin');
            logger.debug('Debug from MyPlugin');
            logger.warn('Warning from MyPlugin');
            logger.error('Error from MyPlugin');
            // 可以通过 logger.warn() logger.error() 等方法输出异常日志,这不会影响webpack的编译结果
            logger.warn('Warning');
            logger.error('Error');
            // 还可以通过compilation.errors和compilation.warnings添加错误和警告
            compilation.errors.push(new Error("Emit Error From FooPlugin"));
            compilation.warnings.push("Emit Warning From FooPlugin");
            callback();
        })
    }
}
module.exports = MyPlugin;

这里可以通过loggerwarnerror方法输出异常日志,也可以通过compilationwarningserrors添加错误警告,他们都不会中断webpack的构建。


他们的区别在于,使用log仅仅是出入错误信息到控制台,而使用compilation.warningscompilation.errors还会将错误信息汇总到 stats 统计对象:


image.png

处理错误信息


上面讲到通过log来记录编译过程中的一些信息,包括错误信息,但是这个错误信息并不会影响构建,其实除了通过log来处理异常还有其他的方式来处理异常。


  1. 直接抛出异常


class MyPlugin {
    apply(compiler) {
        compiler.hooks.emit.tapAsync('MyPlugin', (compilation, callback) => {
            if (Math.random() > 0.5) {
                // 直接抛出异常会中断webpack的构建
                throw new Error('MyPlugin error');
            }
            callback();
        })
    }
}
module.exports = MyPlugin;

  1. 向下透传错误信息


class MyPlugin {
    apply(compiler) {
        compiler.hooks.emit.tapAsync('MyPlugin', (compilation, callback) => {
            let error = undefined;
            if (Math.random() > 0.5) {
                error = new Error('MyPlugin error');
            }
            // callback的第一个参数是错误信息,错误信息会被webpack捕获,如果有错误信息,webpack会停止打包
            callback(error);
        })
    }
}
module.exports = MyPlugin;

上报统计信息


有时候处理一些文件会特别耗时,用户可能需要对此进行一些优化,这个时候就需要插件的开发者提供统计信息了,上报统计信息有两种方式:


  • 使用 ProgressPlugin 插件的 reportProgress 接口上报执行进度;


  • 简单用法:npx webpack --progress


这种方式最终输出的进度和真实的构建进度差别很大(虽然进度条都是假的),因为有些插件可能没有提交任何构建进度相关的信息。


  • 使用webpack提供的ProgressPlugin插件
  • 首先在配置文件中配置一下
const MyPlugin = require('./src/plugin/index')
const {ProgressPlugin} = require('webpack')
module.exports = {
    // 省略其他配置
    plugins: [
        new MyPlugin(),
        new ProgressPlugin({
            activeModules: false,
            entries: true
        })
    ]
}

  • 然后在插件中编写上报进度的代码


const {ProgressPlugin} = require('webpack');
const wait = (misec) => new Promise((r) => setTimeout(r, misec));
class MyPlugin {
    apply(compiler) {
        compiler.hooks.emit.tapAsync('MyPlugin', async (compilation, callback) => {
            // 获取 Reporter ,这个有可能为 null,我这里没有写兜底的空函数
            const reportProgress = ProgressPlugin.getReporter(compiler);
            for (let i = 0; i < 100; i++) {
                await wait(100);
                reportProgress(i / 100, `Our plugin is working ${i}%`);
            }
            callback()
        })
    }
}
module.exports = MyPlugin;

  • 使用 stats 接口汇总插件运行的统计数据。
  • 编写代码
class MyPlugin {
    apply(compiler) {
        compiler.hooks.compilation.tap('MyPlugin', (compilation) => {
            const statsMap = new Map();
            // buildModule 钩子将在开始处理模块时触发
            compilation.hooks.buildModule.tap('MyPlugin', (module) => {
                const ident = module.identifier();
                const startTime = Date.now();
                // 模拟5秒钟的构建时间
                while (new Date().getTime() - startTime < 5000);
                const endTime = Date.now();
                // 记录处理耗时
                statsMap.set(ident, endTime - startTime);
            });
            compilation.hooks.statsFactory.tap('MyPlugin', (factory) => {
                factory.hooks.result
                    .for("module")
                    .tap('MyPlugin', (module, context) => {
                        const { identifier } = module;
                        const duration = statsMap.get(identifier);
                        // 添加统计信息
                        module.fooDuration = duration || 0;
                    });
            });
        })
    }
}
module.exports = MyPlugin;

  • 输出结果:npx webpack --profile --json=compilation-stats.json

这个命令会在根目录创建一个compilation-stats.json的文件,可以找到module.fooDuration就是构建时间,也是上面自己记录的信息,不出意外应该是5000

总结


插件其实就是一个工程项目,提高项目的健壮性是很有必要的一件事,上面的对于插件的开发没有任何帮助,但是对一个软件系统质量提升有很大的帮助,这有益于问题的排查,软件的运行状态,性能等有一个可靠的输出结果来查看,让软件更加可靠。


课程中还讲到了参数校验、测试环境搭建、编写测试用例,但是这些在之前我写loader的时候都有讲过,这里我也就不做记录了。


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
5天前
|
前端开发
【专栏】`webpack` 的 `DefinePlugin` 插件用于在编译时动态定义全局变量,实现环境变量差异化、配置参数动态化和条件编译
【4月更文挑战第29天】`webpack` 的 `DefinePlugin` 插件用于在编译时动态定义全局变量,实现环境变量差异化、配置参数动态化和条件编译。通过配置键值对,如 `ENV: JSON.stringify(process.env.NODE_ENV)`,可以在代码中根据环境执行相应逻辑。实际应用包括动态加载资源、动态配置接口地址和条件编译优化代码。注意变量定义的合法性和避免覆盖,解决变量未定义或值错误的问题,以提升开发效率和项目质量。
|
6天前
|
前端开发 JavaScript API
webpack插件开发必会Tapable
webpack插件开发必会Tapable
55 0
|
6天前
|
缓存 前端开发 API
《Webpack5 核心原理与应用实践》学习笔记-> webpack插件开发基础
《Webpack5 核心原理与应用实践》学习笔记-> webpack插件开发基础
70 0
|
6天前
|
前端开发 JavaScript 测试技术
《Webpack5 核心原理与应用实践》学习笔记-> webpack的loader运行与调试
《Webpack5 核心原理与应用实践》学习笔记-> webpack的loader运行与调试
37 0
|
6天前
|
存储 缓存 JavaScript
《Webpack5 核心原理与应用实践》学习笔记-> webpack的loader开发技巧
《Webpack5 核心原理与应用实践》学习笔记-> webpack的loader开发技巧
47 1
|
6天前
|
缓存 监控 JavaScript
《Webpack5 核心原理与应用实践》学习笔记-> webpack极致性能优化
《Webpack5 核心原理与应用实践》学习笔记-> webpack极致性能优化
33 1
|
6天前
|
前端开发 JavaScript
《Webpack5 核心原理与应用实践》学习笔记-> webpack代码压缩
《Webpack5 核心原理与应用实践》学习笔记-> webpack代码压缩
53 0
|
6天前
|
监控 IDE 开发工具
《Webpack5 核心原理与应用实践》学习笔记-> webpack性能优化技巧
《Webpack5 核心原理与应用实践》学习笔记-> webpack性能优化技巧
68 0
|
6天前
|
JavaScript 前端开发 API
《Webpack5 核心原理与应用实践》学习笔记-> webpack并行构建
《Webpack5 核心原理与应用实践》学习笔记-> webpack并行构建
74 0
|
6天前
|
前端开发 测试技术
《Webpack5 核心原理与应用实践》学习笔记-> webpack核心配置结构
《Webpack5 核心原理与应用实践》学习笔记-> webpack核心配置结构
61 1