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

webpack plugin源码解析(四) HashedModuleIdsPlugin

文章目录

  • 作用
  • 涉及 webpack API
    • 获取chunkGraph
    • 获取当前编译过程中被使用过的 module id:compilation.usedModuleIds
    • 获取当前编译过程中所有的模块对象:compilation.modules
    • 判断 module 是否需要生成 id:module.needId
    • 获取指定module 的 module id:chunkGraph.getModuleId
    • 获取 module 属于多少个chunk:chunkGraph.getNumberOfModuleChunks
    • 获取 module 标识符:module.identifier
    • 设置 module id:chunkGraph.setModuleId
  • 实现
    • constructor
    • apply
    • getUsedModuleIdsAndModules

作用

  • 将模块打包生成后的 id 变成 hash 值,用于生成稳定的模块 id
new webpack.ids.HashedModuleIdsPlugin(),

在这里插入图片描述

涉及 webpack API

  • 获取chunkGraph

const chunkGraph = compilation.chunkGraph;
  • 获取当前编译过程中被使用过的 module id:compilation.usedModuleIds

compilation.usedModuleIds;  //其中一些模块可能会被排除在最终的构建结果之外,因为它们没有被使用过
  • 获取当前编译过程中所有的模块对象:compilation.modules

    • 包括那些被使用过的模块和那些没有被使用过的模块。
for (const module of compilation.modules) {// ...
}
  • 判断 module 是否需要生成 id:module.needId

    • 表示该模块是否需要一个模块 id, 在 webpack 的编译过程中,有些模块可能不需要一个独立的模块 id,例如一些内置模块或者一些被动态加载的模块
for (const module of compilation.modules) {if (!module.needId) continue;const moduleId = chunkGraph.getModuleId(module);
}
  • 获取指定module 的 module id:chunkGraph.getModuleId

for (const module of compilation.modules) {if (!module.needId) continue;const moduleId = chunkGraph.getModuleId(module);
}
  • 获取 module 属于多少个chunk:chunkGraph.getNumberOfModuleChunks

// chunkGraph.getNumberOfModuleChunks 表示 module 属于多少个chunk ,为 0 表示模块对象不属于任何一个 chunk
if (chunkGraph.getNumberOfModuleChunks(module) !== 0){// ...
}
  • 获取 module 标识符:module.identifier

    • 根据 module 的 type、request、layer创建
for (const module of compilation.modules) {module.identifier()
}// module.identifier
identifier() {if (this.layer === null) {if (this.type === "javascript/auto") {return this.request; // "/xxx/Desktop/webpack/wb/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[1].use[0]!/xxx/Desktop/webpack/wb/src/o1.js"} else {return `${this.type}|${this.request}`;}} else {return `${this.type}|${this.request}|${this.layer}`;}
}
  • 设置 module id:chunkGraph.setModuleId

for (const module of compilation.modules) {const moduleId= 'xxx'chunkGraph.setModuleId(module, moduleId);
}

实现

constructor

class HashedModuleIdsPlugin {/*** @param {HashedModuleIdsPluginOptions=} options options object*/constructor(options = {}) {validate(options);/** @type {HashedModuleIdsPluginOptions} */this.options = {context: null,hashFunction: "md4",hashDigest: "base64",hashDigestLength: 4,...options};}
}

apply

apply(compiler) {const options = this.options;compiler.hooks.compilation.tap("HashedModuleIdsPlugin", compilation => {// hooks.moduleIds 为每个模块分配 id 时触发compilation.hooks.moduleIds.tap("HashedModuleIdsPlugin", () => {const chunkGraph = compilation.chunkGraph;const context = this.options.context // "/xxx/Desktop/webpack/wb"? this.options.context: compiler.context;// 获取所有效的 modules 和已经编译使用过的 module idconst [usedIds, modules] = getUsedModuleIdsAndModules(compilation);// 对 modules 排序const modulesInNaturalOrder = modules.sort(compareModulesByPreOrderIndexOrIdentifier(compilation.moduleGraph));for (const module of modulesInNaturalOrder) {// 获取 module 标识,用来创建 hashconst ident = getFullModuleName(module, context, compiler.root); // "./node_modules/babel-loader/lib/index.js??ruleSet[1].rules[1].use[0]!./src/o1.js"const hash = createHash(options.hashFunction);hash.update(ident || "");const hashId = /** @type {string} */ (hash.digest(options.hashDigest));let len = options.hashDigestLength;// 默认取 hash 前四位,如果有重复往后取while (usedIds.has(hashId.slice(0, len))) len++;const moduleId = hashId.slice(0, len);// 更改 module idchunkGraph.setModuleId(module, moduleId);// 添加新 module idusedIds.add(moduleId);}});});
}

getUsedModuleIdsAndModules

  • 获取所有效的 modules 和已经编译使用过的 module id
  • 只有需要生成 module id 的 module 且之前没有创建过且 module 在某个 chunk 中才有效
const getUsedModuleIdsAndModules = (compilation, filter) => {const chunkGraph = compilation.chunkGraph;const modules = [];const usedIds = new Set();// 用于存储在当前编译过程中被使用过的 module id。if (compilation.usedModuleIds) {for (const id of compilation.usedModuleIds) {usedIds.add(id + "");}}// compilation.modules: 存储在当前编译过程中所有的模块对象,包括那些被使用过的模块和那些没有被使用过的模块。for (const module of compilation.modules) {// module.needId 表示该模块是否需要一个模块 id, 在 webpack 的编译过程中,有些模块可能不需要一个独立的模块 id,例如一些内置模块或者一些被动态加载的模块if (!module.needId) continue;// 获取 module id const moduleId = chunkGraph.getModuleId(module);if (moduleId !== null) {// 如果已有则跳过usedIds.add(moduleId + "");} else {// chunkGraph.getNumberOfModuleChunks 表示 module 属于多少个chunk ,为 0 表示模块对象不属于任何一个 chunkif ((!filter || filter(module)) &&chunkGraph.getNumberOfModuleChunks(module) !== 0) {// 将该 module 放入 modules 用于后续计算 module id hash 值modules.push(module);}}}return [usedIds, modules];
};

相关文章:

webpack plugin源码解析(四) HashedModuleIdsPlugin

文章目录作用涉及 webpack API获取chunkGraph获取当前编译过程中被使用过的 module id:compilation.usedModuleIds获取当前编译过程中所有的模块对象:compilation.modules判断 module 是否需要生成 id:module.needId获取指定module 的 module…...

pytorch | 使用vmap对自定义函数进行并行化/ 向量化的执行

0. 参考 pytorch官方文档:https://pytorch.org/docs/stable/generated/torch.func.vmap.html#torch-func-vmap关于if语句如何执行:https://github.com/pytorch/functorch/issues/257 1. 问题背景 笔者现在需要执行如下的功能: root_ls [fu…...

Docker部署RabbitMQ(单机,集群,仲裁队列)

RabbitMQ部署指南 1.单机部署 我们在Centos7虚拟机中使用Docker来安装。 1.1.下载镜像 方式一:在线拉取 docker pull rabbitmq:3-management方式二:从本地加载 在课前资料已经提供了镜像包: 上传到虚拟机中后,使用命令加载镜…...

生活污水处理设备选购指南

生活污水中含有大量的有机物(如蛋白质、碳水化合物、脂肪、尿素、氨氮等)及大量的病原微生物,可导致传染病蔓延流行。因此,生活污水在排放前,需要进行处理。那么如何正确的选择生活污水处理设备呢? 一、生活…...

奥威BI数据可视化大屏分享|多场景、多风格

数据可视化大屏一般应用在品牌推广展示、商务交流、数据分析决策、数据监控等场景,由此催生出各种不同风格的BI数据可视化大屏设计。下面就从奥威BI软件的BI报表模板中截取几个有着不同风格,起着不同作用的BI数据可视化大屏报表,一起来了解一…...

超越时空:加速预训练语言模型的训练

超越时空:加速预训练语言模型的训练 随着自然语言处理(NLP)领域的快速发展,预训练语言模型(PTLM)已成为许多NLP任务的重要基石,如文本生成、情感分析、文本分类等。然而,传统的PTLM…...

数据库管理系统PostgreSQL部署安装完整教程

PostgreSQL是一个开源的关系型数据库管理系统,它支持大量的数据类型和复杂的查询语言,可以用于各种应用程序。它是一个高性能的数据库,可以处理大量的数据,并且具有良好的可扩展性和可靠性。 目录 一.Linux系统安装PostgresSQL&a…...

有学生问我,重构是什么?我应该如何回答?

重构到底是什么?只是代码的推倒重新编码?还是有规则、有方法可寻?当然,结论肯定是有的,本文,我们通过一个简单的实例,来理解一下重构。 1.借助一个实例需求 这是一个影片出租店用的程序&#…...

交际场合---英文单词

目录 前言原文邀请生日和聚会离别探病婚礼新居落成葬礼聚会相关单词婚礼相关单词乔迁相关单词丧礼相关单词前言 加油 原文 邀请 1.invite[ɪnˈvaɪt]vt. 邀请 invitation [ˌɪnvəˈteʃən] n. 邀请;邀请函 invite sb to v. 邀请某人从事…… accept / decline /…...

【网络安全】文件上传漏洞及中国蚁剑安装

文件上传漏洞描述中国蚁剑安装1. 官网下载源码和加载器2.解压至同一目录并3.安装4.可能会出现的错误文件上传过程必要条件代码示例dvwa靶场攻击示例1.书写一句话密码进行上传2. 拼接上传地址3.使用中国蚁剑链接webshell前端js绕过方式服务端校验请求头中content-type黑名单绕过…...

[Java]面向对象高级篇

文章目录包装类包装类层次结构基本类型包装类特殊包装类数组一维数组多维数组可变长参数字符串String类StringBuilder类内部类成员内部类静态内部类局部内部类匿名内部类Lambda表达式方法引用异常机制自定义异常抛出异常异常的处理常用工具类数学工具类随机数数组工具类包装类 …...

苹果应用商店上架流程

上架过程分七个步骤,按步骤一步步来。 仔细看这个流程,少走很多弯路,不用一步步去试错,新手也能快速掌握上架流程。 1、创建APP身份证(App IDs) 2、申请iOS发布证书 3、申请iOS发布描述文件 4、上传ios证…...

基于Eclipse下使用arm gcc开发GD32调用printf

系列目录 第一章 xxx 目录 系列目录 文章目录 文章目录 系列文章目录前言一、pandas是什么?二、使用步骤 1.引入库2.读入数据总结前言 开发环境:Eclipse代替Keil,IAR 开发平台:GD32 开发编译器:arm-none-eabi- …...

5个降低云成本并提高IT运营效率的优先事项

在过去的十年里,公司在公有云和私有云基础设施上构建了大量的计算工作负载,或者将工作负载转移到云端。Gartner 预测,到2023年,全球终端用户在公共云服务上的支出将达到5910亿美元,比2021年增长43%。这是一个显著的增长…...

95-拥塞控制

拥塞控制1.什么是拥塞控制2.拥塞控制的方法(1)慢启动和拥塞避免(2)快速重传和快速恢复1.什么是拥塞控制 在计算机网络中的链路容量(即带宽)、交换结点中的缓存和处理机等,都是网络的资源。在某段时间,若对网络中某一资源的需求超…...

Linux常见操作命令【二】

一、Vi 编辑器 Vi 编辑器存在三者模式:命令、末行、编辑 1.1 命令模式 输入 vi 默认进入命令模式 输入n或者nG:定位到某一行行首 输入G:跳到文件最后一行行首 输入hjkl:表示左下上右移动光标(方向键也可以&#xf…...

Linux驱动中断和定时器

目录 中断 顶半部/底半部机制 软中断: Tasklet: 工作队列: 定时器 中断 中断是正在执行的程序被另一个程序打断,去执行另一个程序的处理函数,当执行完再返回执行被打断的程序。分为内中断(异常)和外中断(硬件中断)。 当cp…...

表达式和函数

表达式: 将数字和运算符连接起来的组合称为表达式。我们可以将数字称为操作数,单个操作数也可以被看作是一个表达式。 操作数:常数,列名,函数调用,其他表达式 运算符:算数运算符,…...

C#基础复习

目录 格式字符串 多重标记和值 预定义类型 用户定义类型 值类型和引用类型 存储引用类型对象的成员 C#类型的分类 静态类型和dynamic关键字 类的基本概念 类成员的类型 为数据分配内存 访问修饰符 格式字符串 多重标记和值 C#程序就是一组类型声明,学习C#就是学习…...

Windows服务器使用代码SSH免密登录并执行脚本

服务器操作系统 Window Server 2016 1、Windows服务器安装OpenSSH 有多种方式,本文介绍一种方式 下载页: https://github.com/PowerShell/Win32-OpenSSH/releases 在下载页下载文件OpenSSH-Win64.zip 本次实验解压至 D:\OpenSSH-Win64\OpenSSH-Win6…...

OpenLayers 可视化之热力图

注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 热力图(Heatmap)又叫热点图,是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建

制造业采购供应链管理是企业运营的核心环节,供应链协同管理在供应链上下游企业之间建立紧密的合作关系,通过信息共享、资源整合、业务协同等方式,实现供应链的全面管理和优化,提高供应链的效率和透明度,降低供应链的成…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析

这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...

如何为服务器生成TLS证书

TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍

文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...

Netty从入门到进阶(二)

二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)

考察一般的三次多项式,以r为参数: p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]; 此多项式的根为: 尽管看起来这个多项式是特殊的,其实一般的三次多项式都是可以通过线性变换化为这个形式…...

并发编程 - go版

1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...

从“安全密码”到测试体系:Gitee Test 赋能关键领域软件质量保障

关键领域软件测试的"安全密码":Gitee Test如何破解行业痛点 在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的"神经中枢"。从国防军工到能源电力,从金融交易到交通管控,这些关乎国计民生的关键领域…...