前端工程化之:webpack1-6(编译过程)

一、webpack编译过程

webpack 的作用是将源代码编译(构建、打包)成最终代码。

整个过程大致分为三个步骤:

  1. 初始化
  2. 编译
  3. 输出

1.初始化

初始化时我们运行的命令 webpack 为核心包, webpack-cli 提供了 webpack 命令,通过命令启动 webpack , webpack 命令就是在调用核心包里面的功能。

此阶段, webpack 会将 CLI 参数(--mode --config等)、配置文件(webpack.config.js)、默认配置进行融合,形成一个最终的配置对象。

对配置的处理过程是依托一个第三方库 yargs 完成的。

此阶段相对比较简单,主要是为接下来的编译阶段做必要的准备。

目前,可以简单的理解为,初始化阶段主要用于产生一个最终的配置。

2.编译

(1)创建 chunk

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

根据入口模块 (默认为 ./src/index.js ) 创建一个 chunk 。

main chunk**=>** 入口模块: ./src/index.js

chunk 可以有多个,每个 chunk 都有至少两个属性:

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

(2)构建所有依赖模块

构建过程入下图:

  1. **模块文件:**首先拿到模块文件 ./src/index.js ,根据路径检查这个模块是否已经加载过。
  2. **已记录则结束,未记录则继续:**根据右侧模块记录表格中的路径找到模块检查是否记录。
  3. **读取文件内容(node环境可以读取文件):**未加载将文件内容读取出来,通过语法分析转换为 AST 抽象语法树。
  4. AST抽象语法树:AST explorer,通过 AST 语法树准确地找到依赖关系,记录依赖,进行树形结构遍历,找到所有依赖.
  5. **保存到 dependencies 中:**将所有依赖保存到 dependencies 数组中,记录完整相对路径即模块 id 。
  6. **替换依赖函数:**将有依赖的地方转换为另一种代码格式,例: require("./a") ,转换为__webpack_require("./src/a.js") ,将 require 转换为 __webpack__require ,将路径转换为绝对路径即模块 id 。
  7. 保存转换后的模块代码:将上图中的模块记录表格保存。模块 id 为完整绝对路径,转换后的代码为示例中index.js - 2代码。

例: index.js - 1

javascript 复制代码
console.log("index");
require("./a");
require("./b");

index.js - 2

javascript 复制代码
console.log("index");
__webpack_require("./src/a.js");
__webpack_require("./src/b.js");

a.js

javascript 复制代码
require("./b");
console.log("a");
module.exports = "a";

b.js

javascript 复制代码
console.log("b");
module.exports = "b";

转换后的chunk中模块记录:

模块id 转换后代码
index.js console.log("index"); __webpack_require("./src/a.js"); __webpack_require("./src/b.js");
a.js __webpack_require("./src/b.js"); console.log("a"); module.exports = "a";
b.js console.log("b"); module.exports = "b";

示例编译过程:

  1. ./src/index.js 未加载。
  2. 内容(字符串): index.js - 1 代码。
  3. --> AST --> 树形结构遍历,找到所有依赖。
  4. dependencies:["./src/a.js","./src/b.js"] 。
  5. index.js - 1 中代码被转换为 index.js - 2 。
  6. 保存转换后的代码。
  7. 循环依赖,重新加载 ./src/a.js 。
  8. 重复1-6过程。
  9. 根据 a.js 文件中的依赖关系,重新加载 ./src/b.js 。
  10. 重复1-6过程,此时 a.js 文件的依赖关系已分析完毕, chunk 模块记录表格已经记录了所有模块信息。
  11. index.js 模块按顺序应该加载 b.js 模块,但是由于 b.js 已经加载过了,为已记录状态。所以不需要重新加载 b.js 模块。
  12. 依赖模块构建结束。

(3)产生 chunk assets

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

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

chunk 中的模块记录:

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

chunk assets :

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

chunk hash:xxxxxxxxxxxxxxxxxxxxxxx

chunk hash 是根据所有 chunk assets 的内容生成的一个 hash 字符串。
hash :一种算法,具体有很多分类,特点是将一个任意长度的字符串转换为一个固定长度的字符串,而且可以保证原始内容不变,产生的 hash 字符串就不变。

(4)合并 chunk assets

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

3.输出

此步骤非常简单, webpack 将利用 node 中的 fs 模块(文件处理模块),根据编译产生的总的 assets ,生成相应的文件。

二、总过程

如果开启watch,每一次文件变化都会重新进行编译。

涉及术语

  1. module :模块,分割的代码单元, webpack 中的模块可以是任何内容的文件,不仅限于 JS 。
  2. chunk : webpack 内部构建模块的块,一个 chunk 中包含多个模块,这些模块是从入口模块通过依赖分析得来的。
  3. bundle : chunk 构建好模块后会生成 chunk 的资源清单,清单中的每一项就是一个 bundle ,可以认为 bundle 就是最终生成的文件。
  4. hash:最终的资源清单所有内容联合生成的 hash 值。
  5. chunkhash: chunk 生成的资源清单内容联合生成的 hash 值。
  6. chunkname: chunk 的名称,如果没有配置则使用 main 。
  7. id:通常指 chunk 的唯一编号,如果在开发环境下构建,和 chunkname 相同;如果是生产环境下构建,则使用一个从 0 开始的数字进行编号。
相关推荐
熊的猫39 分钟前
JS 中的类型 & 类型判断 & 类型转换
前端·javascript·vue.js·chrome·react.js·前端框架·node.js
瑶琴AI前端1 小时前
uniapp组件实现省市区三级联动选择
java·前端·uni-app
会发光的猪。1 小时前
如何在vscode中安装git详细新手教程
前端·ide·git·vscode
我要洋人死2 小时前
导航栏及下拉菜单的实现
前端·css·css3
科技探秘人3 小时前
Chrome与火狐哪个浏览器的隐私追踪功能更好
前端·chrome
科技探秘人3 小时前
Chrome与傲游浏览器性能与功能的深度对比
前端·chrome
JerryXZR3 小时前
前端开发中ES6的技术细节二
前端·javascript·es6
七星静香3 小时前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
q2498596933 小时前
前端预览word、excel、ppt
前端·word·excel
小华同学ai3 小时前
wflow-web:开源啦 ,高仿钉钉、飞书、企业微信的审批流程设计器,轻松打造属于你的工作流设计器
前端·钉钉·飞书