解锁webpack核心技能(三):从源代码到打包产物编译过程的原理指南

编译过程

前言:

当我第一次看到Webpack将一堆零散的文件打包成一个整洁的bundle时,感觉就像在看一场神奇的魔术表演。这个"魔术"的背后,其实是Webpack精妙的编译过程在发挥作用。 Webpack的编译过程就像一条精心设计的流水线,把我们的源代码一步步转化为最终可运行的代码。这个过程主要分为三个关键阶段:

  1. 初始化阶段 - 就像准备烹饪前的食材准备,Webpack会收集并整理所有配置信息
  2. 编译阶段 - 相当于实际的烹饪过程,Webpack会分析代码依赖关系并打包成chunk
  3. 输出阶段 - 就像装盘上菜,Webpack会把处理好的代码写入最终文件

本文将用通俗易懂的方式,带你一步步拆解Webpack的编译魔法,让你不仅知道怎么配置Webpack,更明白为什么要这样配置。无论你是刚接触Webpack的新手,还是想深入理解其工作原理的开发者,这篇文章都将为你提供清晰的指引。

官网这张图简单来说是根据一个入口文件来进行打包成一个结果,中间经过了 webpack 来打包,这个打包的过程叫做编译。webpack 的作用就是把我们左边的源代码打包(编译、构建)成右边的最终代码。编译过程是从左边源代码到右边最终代码的过程。

1. 整个过程大致分为三个步骤:1. 初始化 2. 编译 3. 输出

这三个步骤完成之后就能把我们的初始代码转换为最终代码。

1)初始化:

在初始化这个阶段,webpack 会将 cli 参数、配置文件、默认配置进行融合,形成一个最终的配置对象。像 css 样式表一样,我们自己写的样式以及浏览器的默认样式最终融合成一张很大的样式表那样。

初始化阶段主要用于产生一个最终的配置,为编译阶段做必要准备,产生完整的配置基础。

  • cli 参数、配置文件与默认配置融合
    • cli 参数:运行 webpack 命令时附加的参数(如:npx webpack --mode=development)
    • 配置文件:webpack.config.js 中通过 module.exports 导出的配置
    • 默认文件:未指定时的默认值(如入口默认为 ./src/index.js)
  • 融合机制:类似 CSS 样式表的层叠机制,优先级顺序为:CLI 参数 > 配置文件 > 默认配置,最终生成完整的配置对象供后续阶段使用。
  • 特殊说明:配置文件必须使用 CommonJS 规范(require/module.exports),配置融合过程会实际执行配置文件中的代码。
  • 第三方库 yargs 的作用
    • 核心功能:专门用于处理命令行参数和配置融合
    • 实现特点:
      • 作为 webpack 的依赖库被引入(位于 node_modules 中)
      • 开发者通常不需要直接使用,除非进行底层开发
    • 工作流程:
      • 解析 CLI 输入的原始参数
      • 合并不同来源的配置项
      • 处理配置冲突和默认值

2)编译

  • 创建 chunk

chunk 是 webpack 在内部构建过程中的一个概念,译为块,它表示通过入口模块找到的所有依赖模块的统称。

根据入口模块(默认为 ./src/index.js)创建一个 chunk,称为 main chunk。每一个 chunk 是有名字的,有很多个入口文件,chunk 会有很多个,默认情况下有一个 chunk。

每个 chunk 都有至少两个属性:

    • name:默认为 main
    • id:唯一编号,开发环境和 name 相同,生产环境是一个数字,从 0 开始

接下来是依赖分析

以入口文件为起点分析整个依赖关系链,例如 入口 index.js 依赖 a.js,a.js 又依赖 b.js ,这三个文件共同构成一个 chunk 。

  • 构建所有依赖模块
    • 构建步骤:
      • 确定入口模块
      • 递归分析所有依赖模块
      • 将分析结果打包成一个 chunk
      • 为 chunk 分配 name 和 id 属性

根据这个循环递归最后生成一个 chunk 中的模块记录表格

3)产生 chunk assets

在第二部完成后,chunk 会产生一个模块列表,列表中包含了模块 id 和 模块转换后的代码

接下来,webpack 会根据配置为 chunk 生成一个资源列表,即 chunk assets ,资源列表可以理解为是生成到最终文件的文件名和文件内容。

chunk 中的模块记录

模块id 转换后的代码
./src/index.js xxxxx
./src/a.js xxxxx

chunk assets

文件名 文件内容
./dist/main.js xxxxx
./dist/main.js.map xxxxx

chunk hask:xxxxxxxxxxxxx

chunk hash 是根据所有 chunk assets 的内容生成的一个 hash 字符串

hash:一种算法,具体有很多分类,特点是将一个任意长度的字符串转换为一个固定长度的字符串,而且可以保证原始内容不变,产生的 hash 字符串就不变。功能可以参考 《从源码到dist》 这篇文章。

  • 模块列表结构:包含模块 ID 和 转换后代码的对应关系,如 /src/index.js 对应转换后的 console.log 代码
  • 资源列表本质:是最终生成文件的文件名和内容映射表,如 /dist/main.js 对应打包后的函数代码
  • chunk 中模块列表的生成
    • 生成时机:在编译过程第二步完成后自动生成
    • 内容组成:
      • 模块 ID :如 /src/index.js
      • 转换后代码:经过 webpack 处理的模块代码字符串
  • webpack 生成资源列表
    • 生成依据:根据 webpack 配置进行转换
    • 资源类型:
      • 主文件:如/dist/main.js
      • 映射文件:如 /dist/main.js.map(根据配置可选)
    • 转换方式
      • 将模块列表放入 IIFE 模块,形成文件内容,通过 eval或直接写入方式嵌入代码,如下图

打包后是这样子的:下图

  • 简图
  • 合并 chunk assets

将多个 chunk 的 assets 合并到一起形成一个总的资源列表,并产生一个总的 hash。

3)输出

webpack 利用 node 中的 fs 模块(文件处理模块),根据编译产生的总的 assets,生成相应的文件。

  • 输出过程:称为 emit 阶段
  • 实现方式:使用 node.js 的 fs 模块
  • 输出内容:将资源列表中的每个文件写入磁盘
  • 输出结果:生成最终的打包文件(如 main.js)

把 assets 数组里面记录的文件名和文件内容输出到文件,就可以看到结果了。

2.webpack 编译过程总结

1)编译流程

  • 初始化阶段:
    • 读取命令行参数
    • 导入配置文件并合并配置对象
    • 最终形成完整的配置对象
  • 编译阶段:
    • 将配置对象交给编译器处理
    • 可能生成一个或多个 chunk(代码块)
    • 每个 chunk 必须包含至少一个入口模块

2)模块处理过程

  • 模块收集:
    • 通过入口文件递归查找所有相关模块
    • 生成资源列表(该 chunk 最终包含哪些资源)
  • chunk 标识:
    • 每个 chunk 有自己的 ID 、名称和哈希值
    • 哈希值根据资源列表计算得出
  • 输出阶段:
    • 将所有 chunk 生成的资源合并成完整资源
    • 生成完整的资源哈希
    • 根据资源列表输出到文件(包含文件名和内容等详细信息)
相关推荐
poemyang3 小时前
解锁硬件潜能:Java向量化计算,性能飙升W倍!
java虚拟机·编译原理·jit·向量化计算·smid
Jet_closer_burning16 小时前
前端项目工程化配置webpack与vite
前端·webpack·node.js
poemyang1 天前
Java编译器优化秘籍:字节码背后的IR魔法与常见技巧
java虚拟机·编译原理·ir·即时编译器
用户84913717547162 天前
vue-element-plus-admin 第7期|主题实战:主题定制与国际化
前端框架·前端工程化
poemyang2 天前
“代码跑着跑着,就变快了?”——揭秘Java性能幕后引擎:即时编译器
java·java虚拟机·编译原理·jit·即时编译器
yuanmenglxb20043 天前
构建工具和脚手架:从源码到dist
前端·webpack
ZoeLandia3 天前
Webpack 搭建 Vue3 脚手架详细步骤
前端·vue.js·webpack
五月君_3 天前
见证历史:Vite 首次超越 Webpack!
前端·webpack·node.js
poemyang3 天前
“同声传译”还是“全文翻译”?为何HotSpot虚拟机仍要保留解释器?
java·java虚拟机·aot·编译原理·解释执行