Webpack 核心原理剖析

时至今日,Webpack 已迭代到 5.x 版本,其功能模块的扩充和复杂度的提升使得源码学习成本陡增。官方文档的晦涩表述更是让许多开发者望而却步。然而,理解 Webpack 的核心原理对优化构建流程、定制化打包方案至关重要。本文将通过简化流程和代码示例,剖析 Webpack 的运作机制,帮助读者从本质层面掌握其核心能力,突破“配置工程师”的局限。

Webpack 的核心能力

Webpack 本质上是一个 JavaScript 应用程序的静态模块打包器。它将应用程序中的资源(JS、CSS、图片等)视为模块,分析依赖关系后打包成静态资源文件,官网的动画就能很好的诠释这一点。

请添加图片描述

其核心能力可概括为:

  1. 模块化整合:将分散的代码按依赖关系组织成 chunk。
  2. 资源转换:通过 Loader 系统处理非 JS 文件。
  3. 扩展性:通过 Plugin 系统在构建生命周期中注入自定义逻辑。

基础使用

初始化项目

npm init -y
npm install webpack webpack-cli --save-dev

目录结构

├── package.json
├── webpack.config.js   # 配置文件
└── src├── index.js        # 入口文件├── a.js└── b.js

webpack.config.js

module.exports = {mode: "development",   // 开发模式(不压缩代码)entry: "./src/index.js",devtool: "source-map"  // 生成源码映射
};

src/index.js

console.log("index module");
const a = require('./a.js');
console.log(a);

src/a.js

console.log("a module");
const b = require('./b.js');
console.log(b);
module.exports = 'a';

src/b.js

console.log("b module");
module.exports = 'b';

打包结果分析

执行 npx webpack 后生成的 dist/main.js

(() => {// 初始化、定义了一个模块对象,key为模块的路径,value函数里面的内容就是我们书写的模块的代码var __webpack_modules__ = ({"./src/a.js": ((module, __unused_webpack_exports, __webpack_require__) => {console.log("a module");const b = __webpack_require__("./src/b.js");console.log(b);module.exports = 'a';}),"./src/b.js": ((module) => {console.log("b module");module.exports = 'b';})});// 模块缓存var __webpack_module_cache__ = {};// 定义__webpack_require__函数,就是我们在代码中使用的require函数function __webpack_require__(moduleId) {// 查找缓存中是否有该模块var cachedModule = __webpack_module_cache__[moduleId];if (cachedModule !== undefined) {return cachedModule.exports;}var module = __webpack_module_cache__[moduleId] = {exports: {}};__webpack_modules__[moduleId](module, module.exports, __webpack_require__);return module.exports;}// 入口文件 src/index.js(() => {console.log("index module");const a = __webpack_require__(/*! ./a.js */ "./src/a.js");console.log(a);})();
})()

打包后的核心内容包含:

  1. 模块映射表:以路径为 key,模块代码为 value。
  2. 模块缓存:避免重复加载。
  3. require 函数:实现模块依赖解析。
  4. 入口执行逻辑:立即执行入口模块代码。

那核心问题来了,Webpack 是如何将我们的源代码打包成 dist/main.js 的?

Webpack 的工作流程

Webpack 的进行打包的工作流程可以分为三个主要阶段:

  1. 初始化阶段:合并配置,创建 Compiler 对象,加载插件。
  2. 编译阶段:从入口递归分析依赖,构建模块依赖图。
  3. 输出阶段:按 chunk 生成文件并写入磁盘。

请添加图片描述

初始化阶段

初始化阶段是 Webpack 打包流程的起点,关键步骤

  1. 合并配置(CLI 参数 + 配置文件 + 默认配置)。
  2. 创建 Compiler 对象(核心控制器)。
  3. 加载插件并绑定生命周期钩子。

编译阶段

编译阶段是 Webpack 处理模块的核心阶段,核心过程

  1. 模块转译:Loader 将非 JS 文件转为 JS,生成 AST。
  2. 依赖分析:遍历 AST 提取模块依赖,递归处理。
  3. 生成模块表:记录模块代码、依赖关系和唯一 ID。
// 编译后的模块表示例
const modules = [{id: "./src/a.js",dependencies: ["./src/b.js"],code: `/* 转换后的代码 */`}
];

编译流程图

请添加图片描述

输出阶段

输出阶段是 Webpack 打包流程的最后阶段,主要包括以下步骤:

  1. 生成 chunk:按入口和动态导入规则拆分模块。
  2. 资源封装:将 chunk 转为包含运行时逻辑的 IIFE 函数。
  3. 文件写入:根据输出配置生成最终文件。

经过这三个阶段,Webpack 就实现了将我们的源代码打包成了最终的工程文件了。

但是在构建的整个过程中,由于浏览器只能认识** html、css、js** 这几种格式的文件,所以需要对其他格式的文件进行转换,这个就需要一个工具来实现,就是 Loader 系统

Loader 系统

Loader系统可以将非 JS 文件(如 CSS、图片)转换为 Webpack 可识别的模块,从而纳入到 Webpack 的打包流程中。

请添加图片描述

Loader 的工作原理

Loader 通过定义一个函数,将输入的内容转换为输出的内容。Webpack 会将 Loader 链式调用,每个 Loader 处理完内容后,会将结果传递给下一个 Loader,直到链尾。
Loader 的基本结构如下:

module.exports = function (content) {// 处理内容return processedContent;
};

在 Webpack 配置中,可以通过 module.rules 来指定 Loader:

module.exports = {module: {rules: [{test: /\.js$/,use: 'babel-loader',},{test: /\.scss$/,use: ['style-loader', 'css-loader', 'sass-loader'],},],},
};

在这个配置中,test 指定了要匹配的文件类型,use 指定了要使用的 Loader 。当 Webpack 处理文件时,会根据文件类型选择对应的 Loader 链来处理文件。

除了文件转换之外,Webpack 也需要在特定时机进行一些处理,这个时候需要一个接口的设计,就是 Plugin 系统

Plugin 系统

Plugin 系统是 Webpack 功能扩展的重要机制。通过 Plugin,开发者可以实现各种功能,如代码压缩、提取 CSS、生成 HTML 等。

Plugin的工作原理

Plugin 通过监听 Webpack 的生命周期事件,在特定的时机介入编译过程。Webpack 提供了丰富的钩子(hooks),Plugin 可以通过注册这些钩子来实现功能扩展。

请添加图片描述

Plugin 的基本结构如下:

class SomePlugin {apply(compiler) {// 注册钩子compiler.hooks.someHook.tap('SomePlugin', () => {// 实现插件功能});}
}

apply 函数中,Plugin 可以通过 compiler.hooks 访问各种钩子,并注册回调函数。当 Webpack 执行到对应的生命周期阶段时,会触发这些钩子,从而执行 Plugin 的功能。

总结

Webpack 的核心原理可归结为模块化依赖分析资源整合。通过理解其工作流程的三阶段(初始化、编译、输出),开发者能更高效地配置优化策略,定制 Loader/Plugin 解决个性化需求。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

移植Qt4.8.7到ARM40-A5

移植Qt4.8.7到ARM40-A5 主机平台:Ubuntu 16.04 LTS(x64) 目标平台:ARM40-A5 Qt版本:Qt4.8.7 ARM GCC编译工具链: arm-2014.05-29-arm-none-linux-gnueabi-i686-pc-linux-gnu.tar.bz2 ----------## Qt移植步骤 ## 1、了解Ubuntu&am…

C++_哈希

1. unordered系列关联式容器在C98中,STL提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到$log_2 N$,即最差情况下需要比较红黑树的高度次,当树中的节点非常多时,查询效率也不理想。最好 的查询是&#xf…

Redis 内存管理机制:深度解析与性能优化实践

🧠 Redis 内存管理机制:深度解析与性能优化实践 文章目录🧠 Redis 内存管理机制:深度解析与性能优化实践🧠 一、Redis 内存架构全景💡 Redis 内存组成结构📊 内存占用分布示例⚙️ 二、内存分配…

cargs: 一个轻量级跨平台命令行参数解析库

目录 1.简介 2.安装与集成 3.项目的目录结构及介绍 4.核心数据结构与函数 5.基本使用示例 6.应用案例和最佳实践 7.高级用法 8.与其他库的对比 9.总结 1.简介 cargs 是一个轻量级、无依赖的 C 语言命令行参数解析库,虽然本身是 C 库,但可以无缝…

【数学建模】质量消光系数在烟幕遮蔽效能建模中的核心作用

前言:欢迎各位光临本博客,这里小编带你直接手撕质量相关系数,文章并不复杂,愿诸君耐其心性,忘却杂尘,道有所长!!!! **🔥个人主页:IF’…

Java代码审计实战:XML外部实体注入(XXE)深度解析

Java代码审计实战:XML外部实体注入(XXE)深度解析XML外部实体注入(XXE)是Web应用程序中一种常见但又常常被忽视的漏洞。它利用了XML解析器解析XML文档时,允许引用外部实体这个特性。如果解析器没有禁用外部实…

当服务器出现网卡故障时如何检测网卡硬件故障并解决?

当服务器出现网卡故障时,可能导致网络通信中断,从而影响业务的正常运行。以下是检测网卡硬件故障、诊断问题并解决的详细方法和步骤。1. 网卡故障的常见表现1.1 硬件故障的常见症状网络无法连接:服务器无法访问外部网络或用户无法连接到服务器…

从车辆中心到用户中心:E/E架构的变革与挑战

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…

RPC内核细节(转载)

RPC内核细节(转载) 背景 随着数据量、并发量、业务复杂度的增长,服务化是架构演进必由之路。服务化离不开RPC框架。 RPC服务化的好处 服务化的一个好处就是,不限定服务的提供方使用什么技术选型,能够实现大公司跨团队的技术解耦。 如下图…

SpringAMQP 的发布方确认

前言 这里的发布方确认是以 SpringAMQP 写的,之前我们在前面的篇章中就学过了 使用 Java 原生的SDK编写,当时是发布确认模式,在这里我们将用 Spring 集成的 rabbitmq 方法来编写 开启发布者确认机制需要进行下面的配置,以 yml 为例…

一套自用的git提交规范,可清晰的识别到关联的任务/bug

分享一套自用的git提交规范&#xff0c;可清晰的识别到关联的任务/bug 一、提交信息的基本结构 推荐使用约定式提交的一种变体&#xff0c;结构如下&#xff1a; <类型>(<范围>): <主题> [#<禅道-ID>]<正文>&#xff08;可选&#xff09;<脚注…

从音频到文本实现高精度离线语音识别

会议频繁&#xff0c;记录繁琐&#xff1f;语音转换成文字工具价格高昂&#xff0c;自己手动整理又耗时费力&#xff1f; 它支持本地离线运行&#xff0c;无需联网&#xff0c;所有数据留在本地&#xff0c;隐私安全毫无顾虑&#xff0c;同时它的功能是实时语音转文字&#xf…

SpringMVC 工作原理

SpringMVC 工作原理 SpringMVC 是 Spring 框架中用于构建 Web 应用的核心模块&#xff0c;其工作流程围绕 “前端控制器&#xff08;DispatcherServlet&#xff09;” 展开&#xff0c;通过组件间的协作完成请求处理与响应。理解其工作原理是掌握 SpringMVC 开发的关键&#xf…

HoRain云--Python机器学习神器:Sklearn全解析

&#x1f3ac; HoRain云小助手&#xff1a;个人主页 &#x1f525; 个人专栏: 《Linux 系列教程》《c语言教程》 ⛺️生活的理想&#xff0c;就是为了理想的生活! ⛳️ 推荐 前些天发现了一个超棒的服务器购买网站&#xff0c;性价比超高&#xff0c;大内存超划算&#xff01;…

疯狂星期四文案网第64天运营日记

网站运营第64天&#xff0c;点击观站&#xff1a; 疯狂星期四 crazy-thursday.com 全网最全的疯狂星期四文案网站 运营报告 今日访问量 今日搜索引擎收录情况

设计一个 AB 测试平台

1. 需求明确化 功能需求实验管理 创建、编辑、删除、复制实验设置实验参数&#xff08;变体、权重、目标指标、时长等&#xff09;实验状态管理&#xff08;草稿、运行中、已结束&#xff09;用户分流与分配 支持多种分流策略&#xff08;随机分配、分层分配、定向分配&#xf…

HiCMAE 论文复现:基于 RAVDESS 数据集的音视频情感识别

HiCMAE 论文复现:基于 RAVDESS 数据集的音视频情感识别 1. 项目背景与论文概述 1.1 多模态情感识别背景 多模态情感识别是人工智能领域的重要研究方向,旨在通过结合多种感知模态(如音频、视频、文本等)来更准确地识别人类情感状态。与传统单模态方法相比,多模态方法能够…

HarmonyOS 数据处理性能优化:算法 + 异步 + 分布式实战

摘要 不管是写 App&#xff0c;还是做 IoT 设备开发&#xff0c;数据处理都是绕不开的主题。你可能要处理几百条传感器数据&#xff0c;也可能要应对几十万条用户行为日志。如果算法不够高效&#xff0c;应用就会卡顿甚至直接崩溃。尤其是在 HarmonyOS&#xff08;鸿蒙系统&…

华为麒麟操作系统运维常见知识点

1.开放root账号密码登录。(1)修改/etc/ssh/sshd_config文件中&#xff0c;PermitRootLogin 属性值为yes。PermitRootLogin yes(2)使用passwd命令设置root密码。sudo su 切换到root账户下&#xff0c;使用passwd 设置密码。(3)重启sshd服务。systemctl restart sshd2.避免使用ch…

嵌入式面试|MCU+RTOS技术栈——面试八股文整理3:STM32

目录 1.单片机启动流程 2.看门狗 3.最小系统 4.ROM、RAM、Flash 5.EPROM、EEPROM 6.Bootloader与OTA 7.NAND FLASH 和NOR FLASH 相同点 区别 适用场景 8.CPU、MPU、MCU、SOC、SOPC 9.交叉编译 10.寄存器 寄存器的作用 寄存器与内存的区别 11.Cortex-M3寄存器组…