彻底搞懂Webpack插件

前言

首先我们先回忆一下Webpack插件是如何使用的?下面是一份基础的Webpack配置文件:

let htmlWebpackPlugin = require('html-webpack-plugin');
 
module.exports = {
 mode: 'development',
 entry: {
  main: path.join(__dirname, 'src/index.js')
 },
 output: {
  path: path.join(__dirname, 'dist'),
  filename: '[name].js'
 },
 plugins: [
  new htmlWebpackPlugin({
   template: path.join(__dirname, 'src/index.html')
  })
 ]
}

可以看到,插件都在plugins中,并且这是一个数组,包含了每一个插件的实例化调用,可以给这个实例传一些参数,因此不难看出来,Webpack插件就是一个类。

流程控制

而熟悉Webpack,你一定知道,插件是在整个构建的生命周期中指定的时机来进行一些逻辑操作的,比如你希望在构建开始时控制台打印时间,在构建产物生成时再打印一次时间;或者是希望在构建过程中进行一些特定操作,这就需要了解Webpack背后实现流程控制的原理。而Webpack则是基于tapable这个第三方库来实现的。

tapable是啥?怎么用?看一下这段代码:

xxx.tap等这类写法很符合tapable风格,我们再来看看看下面的代码:

let { SyncHook } = require('tapable');

class MyPlugin{
    constructor(){
        this.hooks = new SyncHook();
    }
    // 注册事件
    registryEvent(eventName, eventFn){
        this.hooks.tap(eventName, () => {
            eventFn();
        });
    }
    // 执行事件
    executeEvent(){
        this.hooks.call();
    }
}

let compiler = new MyHook();

compiler.registryEvent('事件1', () => {
    console.log('事件1执行了');
});

complier.registryEvent('事件2', () => {
    console.log('事件2执行了');
})

complier.executeEvent();

上述代码就是注册事件 -> 触发事件的一个流程,而回到Webpack中,Webpack也具有很多的流程阶段。

Webpack 的构建流程可以大致分为以下几个阶段:

  1. 初始化阶段:Webpack 准备编译环境。
  2. 编译阶段:Webpack 开始编译,读取配置和模块。
  3. 构建阶段:Webpack 处理模块依赖,生成依赖图谱。
  4. 输出阶段:Webpack 根据依赖图谱生成最终的输出文件。
  5. 完成阶段:Webpack 完成构建,输出结果。

在这些阶段中,Webpack 会触发多种钩子(Tapable 提供的 Hooks),插件可以通过这些钩子介入到构建流程中。
例如产出阶段,则是emit代表了构建产物产物前,afterEmit代表了构建产物产出后。Webpack基于Tapable实现了许多的钩子函数:

image.png

因此我们写插件,需要知道这段逻辑在Webpack哪个阶段来执行,因此插件就是套在Tapable hook里的一层逻辑。

就比如这是一个时间记录打印日志的插件,我在两个生命周期阶段打印了当前时间:

const { Compiler } = require('webpack');

class TimePlugin {
  constructor(options) {
    this.options = options;
  }

  apply(compiler) {
    // 监听编译开始的钩子
    compiler.hooks.run.tapAsync('TimePlugin', (compilation, callback) => {
      console.log('编译开始时间:', new Date().toLocaleTimeString());
      callback();
    });

    // 监听编译完成的钩子
    compiler.hooks.done.tap('TimePlugin', (stats) => {
      console.log('编译结束时间:', new Date().toLocaleTimeString());
    });
  }
}

module.exports = TimePlugin;

在这个示例中,TimePlugin 类监听了 run 和 done 两个钩子。run 钩子在每次编译开始时触发,而 done 钩子在编译结束时触发。tapAsync 方法用于异步钩子,允许在回调中处理异步逻辑。

怎么使用呢?也很简单,在webpack.config.js中实例化下就好:

const TimePlugin = require('./TimePlugin');

module.exports = {
  // Webpack 配置...
  plugins: [
    new TimePlugin({ /* 插件选项 */ })
  ]
};

那为什么逻辑需要编写在apply方法中呢?看一下Webpack源码解析plugins的部分:

image.png

相当于做了一层约定,在编译阶段Webpack会去遍历所有的插件,并且调用apply方法,同时把Tapable实例传进去,这样我们就可以在插件中调用所有的生命周期钩子函数了。

看到这里,你已经很熟悉了吧。再看一个Webpack5的官方demo:

class FileListPlugin {
    constructor(fileName1){
        this.fileName = fileName1;
    }
    apply(compiler){
        let self = this;
        const { webpack } = compiler;

        // Compilation 对象提供了对一些有用常量的访问。
        const { Compilation } = webpack;

        // RawSource 是其中一种 “源码”("sources") 类型,
        // 用来在 compilation 中表示资源的源码
        const { RawSource } = webpack.sources;

        compiler.hooks.thisCompilation.tap('fileListDone', (compilation) => {
            compilation.hooks.processAssets.tap(
                {
                    name: self.fileName,
          
                    // 用某个靠后的资源处理阶段,
                    // 确保所有资源已被插件添加到 compilation
                    stage: Compilation.PROCESS_ASSETS_STAGE_SUMMARIZE,
                },
                (assets) => {
                    // "assets" 是一个包含 compilation 中所有资源(assets)的对象。
                    // 该对象的键是资源的路径,
                    // 值是文件的源码

                    // 生成 Markdown 文件的内容
                    const content = '# 这是一级标题';
            
                    // 向 compilation 添加新的资源,
                    // 这样 webpack 就会自动生成并输出到 output 目录
                    compilation.emitAsset(
                        self.fileName,
                        new RawSource(content)
                    );
                }
            )
        });

    }
}

module.exports = FileListPlugin;

代码中涉及到了2个生命周期,thisCompilation代表了Webpack开始编译的阶段;processAssets代表了所有的静态资源已经生成完毕。

这个demo的主要作用是在Webpack编译的靠后阶段,生成了一个markdown文件,同时输出到了output目录中。

结尾

看完希望你对于Wbepack插件机制的了解能更上一层楼,评论区欢迎一起讨论。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/766032.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

认识软件测试

认识软件测试 软件测试能力要求一、软件测试的步骤1.需求2.测试点3.测试用例4.执行测试用例5.缺陷管理6.测试报告 一、测试用例(test case)**用例编写要素**: 测试用例设计方法1.等价类2.边界值3.判定表法4.场景法 软件测试能力要求 软件测试…

张颂文百花提名,男配界笑出“颂”彩

在这个星光熠熠的百花奖舞台上, 张颂文老师犹如一坛陈年老酒,越品越有味, 竟不声不响地提名了最佳男配角!这下可好, 男配界仿佛一夜之间被“颂”风吹得花枝乱颤,笑料百出。你说张颂文老师这演技&#xf…

嵌套组合请求对象的校验与全局捕捉

个人名片 🎓作者简介:java领域优质创作者 🌐个人主页:码农阿豪 📞工作室:新空间代码工作室(提供各种软件服务) 💌个人邮箱:[2435024119qq.com] &#x1f4f1…

怎么压缩图片大小?6种无需牺牲质量的图片压缩方法

经常处理图片的小伙伴都知道,高质量的图片往往会占据电脑大量的存储空间,导致图片传输及存储的不便。因此,掌握如何压缩图片大小变得尤为重要。本文将详细介绍图片压缩的几种方法,帮助你高效地减小图片文件大小,让你的…

【ACM出版,马来西亚-吉隆坡举行】第四届互联网技术与教育信息化国际会议 (ITEI 2024)

作为全球科技创新大趋势的引领者,中国不断营造更加开放的科技创新环境,不断提升学术合作的深度和广度,构建惠及各方的创新共同体。这是对全球化的新贡献,是构建人类命运共同体的新贡献。 第四届互联网技术与教育信息化国际学术会议…

秒懂设计模式--学习笔记(5)【创建篇-抽象工厂】

目录 4、抽象工厂4.1 介绍4.2 品牌与系列(针对工厂泛滥)(**分类**)4.3 产品规划(**数据模型**)4.4 生产线规划(**工厂类**)4.5 分而治之4.6 抽象工厂模式的各角色定义如下4.7 基于此抽象工厂模式以品牌与系…

本地文本向量模型的部署提供兼容openai的接口

前言 之前部署了fastgpt官方文档的一个,提供的一个m3e-large的向量模型打包的docker镜像,虽然使用起来整体效果还可以,但是有些文本向量相似度匹配的结果还是不太满意的,目前,网络上层出不穷的带推理文本向量,想体验一下,于是我基于modelscope库封装了一个兼容open ai的…

有哪些Python书籍是程序员强烈推荐?

有一本升级版的经典Python项目编程书一定要推荐一下。 Python极客项目编程(第2版) 第一版累计销售19万册,豆瓣评分8.4。每个项目都按照【讲解原理-分析需求-代码精讲-知识小结-扩展练习-完整代码】的方式进行讲解,并提供可下载运…

【文档+源码+调试讲解】科研经费管理系统

目 录 目 录 摘 要 ABSTRACT 1 绪论 1.1 课题背景 1.2 研究现状 1.3 研究内容 2 系统开发环境 2.1 vue技术 2.2 JAVA技术 2.3 MYSQL数据库 2.4 B/S结构 2.5 SSM框架技术 3 系统分析 3.1 可行性分析 3.1.1 技术可行性 3.1.2 操作可行性 3.1.3 经济可行性 3.1…

实习总结 --- 内部平台使用

常用术语 CR CR–标准问题分类管理平台:由业务类型-角色-国家-品类-Page定义。 FAQSOP FAQ是端上用户自助的第一道关口,在引导用户进行自助解决上起关键作用 SOP是指标准作业程序,客服SOP是针对用户遇到的具体问题场景,给客服…

论文阅读【时间序列】DSformer

论文阅读【时间序列】DSformer arxive: DSformer: A Double Sampling Transformer for Multivariate Time Series Long-term Prediction github: MTST 分类:多变量时间序列(Multivariate time series) 核心观点 多变量时间序列3个维度信息 …

从零开始实现大语言模型(一):概述

1. 前言 大家好,我是何睿智。我现在在做大语言模型相关工作,我用业余时间写一个专栏,给大家讲讲如何从零开始实现大语言模型。 从零开始实现大语言模型是了解其原理及领域大语言模型实现路径的最好方法,没有之一。已有研究证明&…

ArcGIS中将测绘数据投影坐标(平面坐标)转地理坐标(球面经纬度坐标)

目录 前言1.测绘数据预览1.1 确定带号1.2 为什么是对Y轴分带,而不是对X轴分带? 2 测绘数据转shp2.1 添加数据2.2 显示XY数据2.3 添加经纬度字段2.4 计算经纬度 3.shp数据重投影4.总结 前言 最近在刚好在做一个小功能,将测绘数据转为经纬度坐标…

一些硬件知识(十二)

X电容是接在火线和零线之间,Y电容是接在火零线和地之间。X电容滤除差模干扰,Y电容滤除共模干扰: 高频干扰信号经过X电容后幅度没有变化,相位相差180度: DW01电池管理芯片: M1、M2:这两个为N沟道…

BMA530 运动传感器

型号简介 BMA530是博世(bosch-sensortec)的一款运动传感器。时尚简约的可穿戴设备为功能强大的组件提供了很小的空间。具有先进功能集的下一代加速度计是世界上最小的加速度传感器(1.2 x 0.8 x 0.55 mm)。它专为紧凑型设备而设计&…

本地项目推送到gitlab仓库的保姆级教程

目录 1、安装git (1)Windows系统 (2)Linux系统 2、gitlab创建空白项目 3、创建密钥 4、将密钥添加到gitlab中 5、远程配置 (1)配置全局的用户和邮箱 (2)本地文件夹初始化 …

【代码随想录】【算法训练营】【第52天】 [647]回文子串 [516]最长回文子序列

前言 思路及算法思维,指路 代码随想录。 题目来自 LeetCode。 day 52,周五,开始补作业了~ 题目详情 [647] 回文子串 题目描述 647 回文子串 解题思路 前提:寻找回文子串,子串意味着元素连续 思路:…

Python-Tkinter+Logging+Sqlserver项目结合

参考文章: https://www.jb51.net/article/283745.htm 目录: common(文件夹) – base.py – config_reader.py – dosqlserver.py – log.py txt(空文件夹,后面会自动生成txt文件在该文件夹下面) 1.txt 2.txt env.…

非平稳信号的时频表示-基于本征模态函数(MATLAB)

时频分析思想萌芽于匈牙利物理学家 Gabor 在 1946 年所提出的 Gabor 展开理论,随后以此为基础发展出著名的线性时频变换方法—短时傅里叶变换。短时傅里叶变换假设分析信号在有限时长内具有平稳特性,它首先将时间与频率均为有限支撑的窗函数与分析信号进…

973. 最接近原点的 K 个点-k数组维护+二分查找

973. 最接近原点的 K 个点-k数组维护二分查找 给定一个数组 points ,其中 points[i] [xi, yi] 表示 X-Y 平面上的一个点,并且是一个整数 k ,返回离原点 (0,0) 最近的 k 个点。 这里,平面上两点之间的距离是 欧几里德距离&#…