前端工程化之: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 开始的数字进行编号。
相关推荐
程序猿小D22 分钟前
第二百六十七节 JPA教程 - JPA查询AND条件示例
java·开发语言·前端·数据库·windows·python·jpa
奔跑吧邓邓子1 小时前
npm包管理深度探索:从基础到进阶全面教程!
前端·npm·node.js
前端李易安1 小时前
ajax的原理,使用场景以及如何实现
前端·ajax·okhttp
汪子熙2 小时前
Angular 服务器端应用 ng-state tag 的作用介绍
前端·javascript·angular.js
Envyᥫᩣ2 小时前
《ASP.NET Web Forms 实现视频点赞功能的完整示例》
前端·asp.net·音视频·视频点赞
Мартин.6 小时前
[Meachines] [Easy] Sea WonderCMS-XSS-RCE+System Monitor 命令注入
前端·xss
昨天;明天。今天。7 小时前
案例-表白墙简单实现
前端·javascript·css
数云界7 小时前
如何在 DAX 中计算多个周期的移动平均线
java·服务器·前端
风清扬_jd7 小时前
Chromium 如何定义一个chrome.settingsPrivate接口给前端调用c++
前端·c++·chrome
安冬的码畜日常7 小时前
【玩转 JS 函数式编程_006】2.2 小试牛刀:用函数式编程(FP)实现事件只触发一次
开发语言·前端·javascript·函数式编程·tdd·fp·jasmine