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

Webpack基本概念及核心流程

什么是Webpack

Webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 Webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。

在下图中可以看出,Webpack 将左侧错综复杂的各自不同类型文件的模板依赖关系,包括 .js、.hbs、.cjs、.sass、.jpg、.png 等类型文件,打包成 .js、.css、.jpg、.png 4 种类型的静态资源。

简单来说,Webpack 就是一个静态资源打包工具,负责将项目中依赖的各个模块,打包成一个或多个文件。

在这里插入图片描述

它的主要功能包括:

1)模块打包

将项目中的所有模块(JavaScript、CSS、图片等)当作一个整体,通过依赖关系将它们打包成一个或多个静态资源文件

2)依赖管理

Webpack 可以分析模块之间的依赖关系,根据配置的入口文件找出所有依赖的模块,并将其整合到打包结果中

3)文件转换

Webpack 本身只能处理 JavaScript 模块,但通过加载器(Loader)的使用,可以将其他类型的文件(如CSS、LESS、图片等)转换为有效的模块,使其能够被打包到最终的结果中

4)代码拆分

Webpack 支持将代码拆分成多个模块,按需加载,实现按需加载和提升应用性能

5)插件系统

Webpack 提供了丰富的插件系统,可以通过插件实现各种功能的扩展,例如压缩代码、自动生成 HTML 文件等

基本概念

dependency graph(依赖图)

依赖图指的就是各个模块之间的依赖关系,例如模块 A 导入了模块 B,则在依赖图中,模块 A 会指向模块 B,如上文引入过的图:

在这里插入图片描述

构建依赖图的主要步骤如下:

1)解析入口文件

从配置文件中指定的入口文件(如index.js)开始解析,入口文件是打包的起点

2)查找依赖

Webpack 会解析入口文件中的代码,查找所有通过importrequire或其他方式引入的模块,例如以下代码,Webpack 会找到vue./styles.css这两个依赖

import Vue from 'vue';
import './styles.css';

3)递归解析

对于每个找到的依赖,Webpack 会继续递归解析其内部的依赖。例如./styles.css文件中可能又引入了其他 CSS 文件或图片资源,Webpack 会继续解析这些资源

4)构建图结构

在解析过程中,Webpack 会将每个文件作为图中的一个节点,并根据依赖关系建立边,最终形成一个完整的依赖图

entry(入口)

入口是指依赖关系图的开始,从入口开始寻找依赖,打包构建。Webpack 允许一个或多个入口配置,配置示例如下:

module.exports = {entry: 'index.js',
};

在这里插入图片描述

output(输出)

输出则是用于配置 Webpack 构建打包的出口,如打包的位置、文件名等,配置示例如下:

module.exports = {output: {path: path.resolve(__dirname, 'dist'),filename: 'my-first-webpack.bundle.js',},
};

在这里插入图片描述

loader(加载器)

Webpack 自带 JavaScript 和 JSON 文件的打包构建能力,无需格外配置。而其他类型的文件,如 CSS、TypeScript,则需要安装 loader 来进行处理,它让 Webpack 能够去处理其他类型的文件,并将它们转换为有效模块。配置示例如下:

module.exports = {module: {rules: [{ test: /.txt$/, use: 'raw-loader' }],},
};

在这里插入图片描述

plugin(插件)

插件则是用于扩展 Webpack 的能力,常见的插件有:

  • ProgressBarPlugin:编译进度条
  • BundleAnalyzerPlugin:打包体积分析
  • MiniCssExtractPlugin:提取 CSS 到独立 bundle 文件

mode(模式)

Webpack5 提供了模式选择,包括开发模式、生产模式、空模式,并对不同模式做了对应的内置优化,可通过配置模式让项目性能更优,配置示例如下:

module.exports = {mode: 'development',
};

resolve(解析)

resolve 用于控制模块的解析规则,通过配置 resolve,Webpack 可以更高效地解析模块路径,找到正确的文件,并处理不同类型的模块。常见的配置项如下:

  • alias:为模块路径设置别名,简化模块引入
  • extensions:用于指定在解析模块时自动尝试的文件扩展名,在引入模块时可不带后缀
  • modules:指定 Webpack 在解析模块时应该查找的目录,默认情况下会查找 node_modules 目录
  • symlinks:控制是否解析符号链接,禁用可提升编译速度

配置示例如下:

module.exports = {resolve: {extensions: ['.js', '.jsx', '.ts', '.tsx', '.json', '.d.ts'],alias: {'@': path.resolve(__dirname, 'src'),'components': path.resolve(__dirname, 'src/components')}modules: [path.resolve(__dirname, 'src'), 'node_modules'], // 先查找 src 目录,再查找 node_modulessymlinks: false,}
}

optimization(优化)

optimization 用于自定义 Webpack 的内置优化配置,一般用于生产模式提升性能,常用配置项如下:

  • minimize:是否需要压缩 bundle
  • minimizer:配置压缩工具,如 TerserPlugin、OptimizeCSSAssetsPlugin
  • splitChunks:拆分 bundle
  • runtimeChunk:是否需要将所有生成 chunk 之间共享的运行时文件拆分出来

配置示例如下:

module.exports = {optimization: {minimizer: [// 在 webpack@5 中,你可以使用 `...` 语法来扩展现有的 minimizer(即 `terser-webpack-plugin`),将下一行取消注释// `...`,new CssMinimizerPlugin(),],splitChunks: {// include all types of chunkschunks: 'all',// 重复打包问题cacheGroups:{vendors:{ //node_modules里的代码test: /[\/]node_modules[\/]/,chunks: "all",name: 'vendors', //chunks namepriority: 10, //优先级enforce: true }}},},
}

核心流程

Webpack 核心功能:将各种类型的资源,包括图片、css、js 等,转译、组合、拼接、生成 JS 格式的 bundler 文件,这个过程核心完成了内容转换 + 资源合并两种功能,实现上包含三个阶段:初始化阶段、构建阶段、生成阶段,单次构建过程自上而下按顺序执行。

初始化阶段

1)初始化参数:从配置文件、 配置对象、Shell 参数中读取,与默认配置结合得出最终的参数

2)创建编译器对象:用上一步得到的参数创建 Compiler 对象

3)初始化编译环境:包括注入内置插件、注册各种模块工厂、初始化 RuleSet 集合、加载配置的插件等

4)开始编译:执行compiler对象的run方法

5)确定入口:根据配置中的entry找出所有的入口文件,调用compilition.addEntry将入口文件转换为 dependence 对象

构建阶段

构建阶段从entry开始递归解析资源与资源的依赖,在compilation对象内逐步构建出module集合以及module之间的依赖关系,核心流程:

在这里插入图片描述

从上图看出,构建阶段从入口文件开始:

  • 调用handleModuleCreate ,根据文件类型构建module子类

  • 调用 loader-runner 仓库的runLoaders转译module内容,通常是从各类资源类型转译为 JS 文本

  • 调用 acorn 将 JS 文本解析为 AST

  • 遍历 AST,触发各种钩子

    • 监听exportImportSpecifier钩子,解读 JS 文本对应的资源依赖
    • 调用module对象的addDependency将依赖对象加入到 module 依赖列表中
  • AST 遍历完毕后,调用module.handleParseResult处理模块依赖

  • 对于module新增的依赖,调用handleModuleCreate,控制流回到第一步

  • 所有依赖都解析完毕后,构建阶段结束

这个过程中数据流:module => ast => dependences => module ,先转 AST 再从 AST 找依赖,这就要求loaders处理完的最后结果必须是可以被 acorn 处理的标准 JavaScript 语法。比如说对于图片,需要从图像二进制转换成 base64 格式或 url 格式。

compilation按这个流程递归处理,逐步解析出每个模块的内容以及module依赖关系,后续就可以根据这些内容打包输出。

生成阶段

基础流程

构建阶段围绕module展开,生成阶段则围绕chunks展开。经过构建阶段之后,Webpack 得到足够的模块内容与模块关系信息,接下来开始生成最终资源了。代码层面就是开始执行compilation.seal函数:

// 取自 webpack/lib/compiler.js 
compile(callback) {const params = this.newCompilationParams();this.hooks.beforeCompile.callAsync(params, err => {// ...const compilation = this.newCompilation(params);this.hooks.make.callAsync(compilation, err => {// ...this.hooks.finishMake.callAsync(compilation, err => {// ...process.nextTick(() => {compilation.finish(err => {**compilation.seal**(err => {...});});});});});});}

seal函数主要完成 module chunks 的转化,核心流程:

在这里插入图片描述

简单梳理一下:

  • 构建本次编译的ChunkGraph对象
  • 遍历compilation.modules集合, module entry/动态引入 的规则分配给不同的 Chunk 对象
  • compilation.modules集合遍历完毕后,得到完整的chunks集合对象,调用createXxxAssets方法
  • createXxxAssets遍历module/chunk ,调用compilation.emitAssets方法将assets信息记录到compilation.assets对象中
  • 触发seal回调,控制流回到compiler对象

这一步的关键逻辑是将module按规则组织成chunks ,Webpack 内置的 chunk 封装规则比较简单:

  • entry entry 触达到的模块,组合成一个chunk
  • 使用动态引入语句引入的模块,各自组合成一个chunk

chunk是输出的基本单位,默认情况下这些chunks与最终输出的资源一一对应,那按上面的规则大致上可以推导出一个entry会对应打包出一个资源,而通过动态引入语句引入的模块,也对应会打包出相应的资源

SplitChunksPlugin的作用

上面提到 Webpack 主流程里面是按entry / 动态引入两种情况组织chunks的,这必然会引发一些不必要的重复打包,而SplitChunksPlugin能将多个模块中重复的代码提取到一个单独的chunk中,这样可以避免在多个文件中重复加载相同的代码,从而减少最终打包文件的体积。

SplitChunksPlugin的拆分过程分为以下几个步骤:

1)模块依赖分析:通过 Webpack 的模块依赖图,识别出被多个chunk共同引用的模块

2)应用拆分规则:根据配置的规则(如minSizeminChunkschunks等),筛选出符合条件的模块

3)创建新的chunk:将符合条件的模块移动到一个新的 chunk ,并更新模块依赖关系

4)生成最终的打包文件:根据更新后的依赖关系,生成最终的打包文件

资源形态流转

上面已经把逻辑层面的构造主流程梳理完了,这里结合资源形态流转的角度重新考察整个过程:

在这里插入图片描述

compiler.make阶段:

  • entry文件以dependence对象形式加入compilation的依赖列表,dependence对象记录有entry的类型、路径等信息
  • 根据dependence调用对应的工厂函数创建module对象,之后读入module对应的文件内容,调用loader-runner对内容做转化,转化结果若有其它依赖则继续读入依赖资源,重复此过程直到所有依赖均被转化为 module

compilation.seal阶段:

  • 遍历module集合,根据entry配置及引入资源的方式, module 分配到不同的 chunk
  • 遍历chunk集合,调用compilation.emitAsset方法标记chunk的输出规则,即转化为 assets 集合

compiler.emitAssets阶段:

  • assets 写入文件系统
http://www.dtcms.com/a/304992.html

相关文章:

  • Docker初学者需要了解的几个知识点(一):传统虚拟机 VS容器
  • vscode开发微信小程序
  • Shader开发(四)计算机图形学中的颜色定义
  • pthread库和thread库
  • 42、鸿蒙HarmonyOS Next开发:应用上下文Context
  • 20250729使用WPS打开xlsx格式的电子表格时候隐藏显示fx的编辑栏的方法
  • Linux ssh服务安装、启动与开机自启
  • ESim电工仿真软件(电脑版)使用说明
  • 在CSS中,如果你想设置一个元素的高度(height)与其宽度(width)相匹配,但又希望宽度使用百分比来定义,你可以通过几种方式来实现。
  • imx6ull-驱动开发篇2——字符设备驱动开发步骤
  • Cursor(编程ai) 使用 - 2025.7.26
  • Linux - 权限的理解(深入浅出,详细细微)
  • 安装新的cuda在bashrc中更新路径
  • Java中的代理
  • 2025年06月03日 Go生态洞察:语法层面的错误处理支持
  • word中rtf格式介绍
  • 游戏分享网站|基于SprinBoot+vue的游戏分享网站系统(源码+数据库+文档)
  • #C语言——学习攻略:深挖指针路线(三)--数组与指针的结合、冒泡排序
  • 前端路由
  • Mysql 图形化界面
  • JVM全面解析
  • 【HTML】浅谈 script 标签的 defer 和 async
  • JAVA中JDK8新特性(Stream流)
  • Unity打包后,在Windows7系统上无法播放VideoPlayer视频
  • Python 中数据的位运算和状态编码(掩码)详解
  • SeeMoE:从零开始实现一个MoE视觉语言模型
  • 项目质量如何把控?核心要点分析
  • Python入门第四课:高级特性与实战:应用列表推导式与生成器
  • Makefile 与 CMake 关系指南
  • 基于 xlsx-js-style 的 Excel 导出工具实现导出excel