手写Webpack-Plugin

Plugin原理

一、Plugin作用

通过插件我们可以扩展webpack,使webpack可以执行更广泛的任务,拥有更强的构建能力。

Plugin工作原理

webpack 就像一条生产线,要经过一系列处理流程后才能将源文件转换成输出结果。 这条生产线上的每个处理流程的职责都是单一的,多个流程之间有存在依赖关系,只有完成当前处理后才能交给下一个流程去处理。 插件就像是一个插入到生产线中的一个功能,在特定的时机对生产线上的资源做处理。webpack 通过 Tapable 来组织这条复杂的生产线。 webpack 在运行过程中会广播事件,插件只需要监听它所关心的事件,就能加入到这条生产线中,去改变生产线的运作。 webpack 的事件流机制保证了插件的有序性,使得整个系统扩展性很好。 ——「深入浅出 Webpack」

站在代码逻辑的角度就是:webpack在编译过程中,会触发一些列 Tapable钩子事件,插件所做的就是找到相应的钩子,往上面挂载自己的任务,也就是注册事件,这样,当webpack执行到相关的钩子函数时就会触发我们挂载的任务事件。

Webpack内部钩子

Tapable

Tapable 为 webpack 提供了统一的插件接口(钩子)类型定义,它是 webpack 的核心功能库。webpack 中目前有十种 hooks,在 Tapable 源码中可以看到,他们是:

// https://github.com/webpack/tapable/blob/master/lib/index.js
exports.SyncHook = require("./SyncHook");
exports.SyncBailHook = require("./SyncBailHook");
exports.SyncWaterfallHook = require("./SyncWaterfallHook");
exports.SyncLoopHook = require("./SyncLoopHook");
exports.AsyncParallelHook = require("./AsyncParallelHook");
exports.AsyncParallelBailHook = require("./AsyncParallelBailHook");
exports.AsyncSeriesHook = require("./AsyncSeriesHook");
exports.AsyncSeriesBailHook = require("./AsyncSeriesBailHook");
exports.AsyncSeriesLoopHook = require("./AsyncSeriesLoopHook");
exports.AsyncSeriesWaterfallHook = require("./AsyncSeriesWaterfallHook");
exports.HookMap = require("./HookMap");
exports.MultiHook = require("./MultiHook");

Tapable 还统一暴露了三个方法给插件,用于注入不同类型的自定义构建行为:

  • tap:可以注册同步异步钩子
  • tapAsync:回调方式注册异步钩子
  • tapPromise:Promise方式注册异步钩子

Plugin构建对象

Compiler

compiler 对象中保存着完整的 Webpack 环境配置,每次启动 webpack 构建时它都是一个独一无二,仅仅会创建一次的对象。

这个对象会在首次启动 Webpack 时创建,我们可以通过 compiler 对象上访问到 Webapck 的主环境配置,比如 loader 、 plugin 等等配置信息。
它有以下主要属性:

  • compiler.options 可以访问本次启动 webpack 时候所有的配置文件,包括但不限于 loaders 、 entry 、 output 、 plugin 等等完整配置信息。
  • compiler.inputFileSystem 和 compiler.outputFileSystem 可以进行文件操作,相当于 Nodejs 中 fs。
  • compiler.hooks 可以注册 tapable 的不同种类 Hook,从而可以在 compiler 生命周期中植入不同的逻辑。

Compilation

compilation 对象代表一次资源的构建,compilation 实例能够访问所有的模块和它们的依赖。
一个 compilation 对象会对构建依赖图中所有模块,进行编译。 在编译阶段,模块会被加载(load)、封存(seal)、优化(optimize)、 分块(chunk)、哈希(hash)和重新创建(restore)。
它有以下主要属性:

  • compilation.modules 可以访问所有模块,打包的每一个文件都是一个模块。
  • compilation.chunks chunk 即是多个 modules 组成而来的一个代码块。入口文件引入的资源组成一个 chunk,通过代码分割的模块又是另外的 chunk。
  • compilation.assets 可以访问本次打包生成所有文件的结果。
  • compilation.hooks 可以注册 tapable 的不同种类 Hook,用于在 compilation 编译模块阶段进行逻辑添加以及修改。
    在这里插入图片描述

开发一个Plugin插件

一个简单的插件构成

class TestPlugin {
  constructor() {
    console.log("TestPlugin constructor()");
  }
  // 1. webpack读取配置时,new TestPlugin() ,会执行插件 constructor 方法
  // 2. webpack创建 compiler 对象
  // 3. 遍历所有插件,调用插件的 apply 方法
  apply(compiler) {
    console.log("TestPlugin apply()");
  }
}

module.exports = TestPlugin;

手动实现生成文件大小分析文件插件

// plugins/analyze-webpack-plugin.js
class AnalyzeWebpackPlugin {
  apply(compiler) {
    // emit是异步串行钩子
    compiler.hooks.emit.tap("AnalyzeWebpackPlugin", (compilation) => {
      // Object.entries将对象变成二维数组。二维数组中第一项值是key,第二项值是value
      const assets = Object.entries(compilation.assets);

      let source = "# 分析打包资源大小 \n| 名称 | 大小 |\n| --- | --- |";

      assets.forEach(([filename, file]) => {
        source += `\n| ${filename} | ${file.size()} |`;
      });

      // 添加资源
      compilation.assets["analyze.md"] = {
        source() {
          return source;
        },
        size() {
          return source.length;
        },
      };
    });
  }
}

module.exports = AnalyzeWebpackPlugin;

在webpack.config.js中配置

const AnalyzeWebpackPlugin = require("./plugins/analyze-webpack-plugin");
//...省略
   plugins: [
        new HtmlWebpackPlugin({
            template: path.resolve(__dirname, 'public/index.html')
        }),
        new AnalyzeWebpackPlugin()
    ],

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

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

相关文章

LeetCode讲解篇之90. 子集 II

文章目录 题目描述题解思路题解代码 题目描述 题解思路 初始化一个变量start表示当前从哪里开始遍历nums 搜索过程的数字组合加入结果集 从start开始遍历nums 如果当前元素和前一个元素相等,前一个元素没被使用,则触发剪枝去重操作,跳过当…

[蓝桥学习] 并查集

并查集基础 并查集用来存储图中结点的连通关系。 一个点的根结点是该点的父亲的父亲的...父亲,根:某个结点的父亲是自己 当两个点的根相同时,就说他们是同一类的,连通的 找根 但是,如果点特别多且形成链的话&#x…

【MySQL】本地创建MySQL数据库详解

文章目录 下载MySQL安装重置密码本地连接 下载MySQL 下载网址:https://dev.mysql.com/downloads/mysql/ 安装 将下载好的压缩包解压到D盘。 在解压好的文件夹中创建my.ini文件。 将以下代码复制粘贴到创建好的my.ini文件中。注意修改文件路径。 [mysqld] #设置…

2024/1/14周报

文章目录 摘要Abstract文献阅读题目问题与创新方法A.CEMDAN方法B.LSTM网络C. CEEMDAN-LSTM模型 实验过程数据集与数据预处理参数设置评价指标和参数 实验结果 深度学习GRUGRU前向传播GRU的训练过程 总结 摘要 本周阅读了一篇基于CEEMDAN-LSTM的金融时间序列预测模型的文章&…

FineBI实战项目一(22):各省份订单个数及订单总额分析开发

点击新建组件,创建各省份订单个数及订单总额组件。 选择自定义图表,将province拖拽到横轴,将cnt和total拖拽到纵轴。 调节纵轴的为指标并列。 修改横轴和纵轴的标题。 修改柱状图样式: 将组件拖拽到仪表板。 结果如下:…

windows同时安装mysql5.0和8.0步骤(完美测试)

mysql5.0和mysql8.0配置如下 1.把如下配置复制下替换到my.ini中 mysql5.0配置如下 [mysqld] # 设置3306端口 port3306 # 设置mysql的安装目录 basedirF:\mysql-5.7.38 # 设置mysql数据库的数据的存放目录 datadirF:\mysql-5.7.38\data # 允许最大连接数 max_connections200 #…

【linux驱动开发】在linux内核中注册一个杂项设备与字符设备以及内核传参的详细教程

文章目录 注册杂项设备驱动模块传参注册字符设备 开发环境: windows ubuntu18.04 迅为rk3568开发板 注册杂项设备 相较于字符设备,杂项设备有以下两个优点: 节省主设备号:杂项设备的主设备号固定为 10,在系统中注册多个 misc 设备驱动时&…

JRebel热部署

热部署 什么热部署,简单来说我们正常的java项目需要编写java代码,但电脑执行的可不是java代码,而是转换后的class文件。这也意味着我们对程序进行微调,也要重新编译才能让程序展示我们需要的状态 而且不仅仅是我们手写的java文件…

统计学-R语言-4.3

文章目录 前言直方图茎叶图箱线图练习 前言 本篇介绍的是数值型数据怎么进行数据可视化,本篇介绍的有直方图、茎叶图、箱线图。 直方图 直方图(Histogram)用于描述连续型变量的频数分布,实际应用中常用于考察变量的分布是否对称…

谷粒商城P139集——云服务器frp内网穿透+nginx完美解决方案

1、修改本地HOST C:\Windows\System32\drivers\etc 目录下 host文件 上面前面是自己的云服务器ip 测试:如域名为gulimall.com 备注如果自己的云服务器nginx端口不是80 访问的时候记得打开 可以访问9200或者nacos尝试 则在浏览器中输入gulimall.com:9200&#xf…

解决“Ubuntu系统与windows系统之间不能执行复制粘贴”之问题

在win11中,发现“Ubuntu系统与windows系统之间不能互相复制粘贴”,只能通过“FPT客户端FileZilla”才能交换文件,但遇到字符串,就没法实现了,因此,在两个系统之间实现互相复制和粘贴字符串,就很…

x86是什么?

x86是一系列CPU架构的统称,这一术语起源于1978年,当时Intel发布了其首款16位微处理器——8086。这款处理器在当时引起了极大的关注,因为它首次引入了许多先进的技术,如寄存器间接寻址和分段内存管理等。随后,Intel又相…

【InternLM 大模型实战】第四课

XTuner 大模型单卡低成本微调实战 FINETUNE简介指令跟随微调增量预训练微调LoRA & QLoRA XTuner简介功能亮点适配多种生态适配多种硬件 8GB 显卡玩转LLMFlash AttentionDeepSpeed ZeRO 动手实战环节环境配置微调准备配置文件模型下载数据集下载修改配置文件开始微调将得到的…

中间人攻击如何进行防护

中间人攻击(Man-in-the-Middle Attack,简称 MITM 攻击)是一种常见的网络攻击方式,攻击者通过截获两个通信实体之间的通信数据,并在此基础上进行篡改、窃取或伪造等恶意行为。这种攻击方式因其攻击手段的隐蔽性和难以防…

LeetCode讲解篇之47. 全排列 II

文章目录 题目描述题解思路题解代码 题目描述 题解思路 初始化一个nums中元素是否被访问的数组used、记录还需要递归的深度deep,遍历nums,如果当前元素被访问过或者当前元素等于前一个元素且前一个元素没被访问过就跳过该次遍历,否则选择当前…

基于SSM+vue的篮球场预约管理系统(Java毕业设计)

大家好,我是DeBug,很高兴你能来阅读!作为一名热爱编程的程序员,我希望通过这些教学笔记与大家分享我的编程经验和知识。在这里,我将会结合实际项目经验,分享编程技巧、最佳实践以及解决问题的方法。无论你是…

mac上部署单体hbase

1. 简介 HBase 是一个开源的、分布式的、版本化的典型非关系型数据库。它是 Google BigTable 的开源实现,并且是 Apache 基金会的 Hadoop 项目的一部分1。HBase 在 Hadoop Distributed File System (HDFS) 上运行,作为一个列式存储非关系数据库管理系统…

JFinal综合信息管理系统

项目地址:mendianyu/AdvancedManagement: 综合信息管理系统 (github.com) 项目演示地址:软件构造大作业演示视频_哔哩哔哩_bilibili 项目功能 一:基于Jfinal构建信息管理系统,要求包含用户管理,翻译业务模块管理&…

redis复习总结

我的redis 1. redis集群 主从集群【哨兵集群】:主从集群是指中,存在一个master节点和多个slave节点。master节点负责接收客户端的读写,slave节点负责读操作。主节点一旦接收到数据的变更,就会将数据同步至slave节点。 但这样的…

集合(二)Collection集合Set

一、Set介绍: 是一个散列的集合,数据会按照散列值存储的,如两个hello的散列值相同,会存储在同一个地址中,所以看到的就是只有一个hello在集合中了。 1、Set集合有两个主要的实现子类:Hashset和Treeset。ha…