上一篇文章问题答案
- 配置内容如下,下面的代码会输出什么?
const path = require('path');
console.log(a);
module.exports = {
mode: "development",
entry: "./src/index.js",
output: {
filename: "js/main.js",
},
devtool: 'source-map',
}
答:会报错 “ a is not defined ”。因为 webpack 进行打包的过程中会运行 webpack.config.js 文件中的代码。
- webpack 打包后的 js 文件代码中有很多重复冗余的代码,会导致什么问题?
答:首先这个问题有一处坑,问的是“打包后的 js 文件中有重复代码”,很多人看到这个问题肯定第一时间想到的是有关解决冗余代码的答案,其实不对。因为,我们在开发阶段期间,已经把公共代码抽离成一个单独的模块,是不存在冗余代码的问题。当入口模块需要使用时 require 导入模块,webpack 为入口模块做模块依赖分析时,自然会合并其他模块代码,所以打包后的 js 文件肯定是有重复代码的。故该问题的核心点是问webpack 打包过程中的影响。
标准答法: 打包后的 js 是 webpack 通过源码编译后生成的,开发阶段是只需要维护源码不需要维护打包后结果。 每个页面对应的 js 中依赖的公共模块相同,并且公共模块代码较多时,在打包过程中会增加一定的传输量。其他的没有影响。
来一张核心图
编译过程分析
webpack 的编译的核心点就是:对源代码的模块进行依赖分析,最终输出编译后打包的结果,依赖分析的过程就是编译的过程。
上一篇笔记中有介绍过 webpack 的三个阶段,这里再过一过眼:
- webpack 初始化:读取配置命令参数,合成配置文件,获取配置对象;
- webpack 编译过程:根据配置对象打包编译源代码;
- webpack 编译结果输出:根据配置对象输出对应的资源清单;
灵魂画手的图
这篇笔记主要详细介绍 webpack 的第二个阶段——编译过程,刨析 webpack 是如何根据配置对象信息,进行编译生成最终的资源清单。
编译的流程
- 根据配置对象中的
entry 属性,webpack 获取入口模块(以./src/index.js 为例)的 ID; - webpack 首先会根据模块 ID 值,检查该模块是否已被记录过(webpack 内部维护的模块表格);(对应模块缓存机制)
- 如果已被记录在模块表格中,则直接返回模块 ID 对应的文本,结束该模块的编译流程;如果未被记录在模块表格,webpack 会读取模块内容;
- webpack 对读取出来的模块内容进行抽象语法树分析(AST);
- 根据抽象语法树分析的结果,webpack 获取到
./src/index.js 模块依赖的其他模块(通过 require 导入的模块),并把依赖的模块保存至入口模块(./src/index.js )的 dependences 数组中(记录模块依赖关系); - 然后,webpack 替换导入、导出函数,替换之后叫替换后的模块代码;
- webpack 保存
./src/index.js 模块 ID 及其替换后的模块代码至模块表格中;(对应缓存模块) - 至此,入口模块(
./src/index.js )编译完成; - 然后,webpack 开始遍历入口模块(
./src/index.js )的 dependences 数组,此时入口模块就变成 dependences 数组中的元素,流程重新从步骤(2)开始; - webpack 递归处理入口模块(
./src/index.js )的 dependences 数组进行编译,直至处理完毕。
编译流程图
一些专业术语
- module:模块,代码分割的单元,webpack 中的模块可以是任何文件,不只 JS 文件;
- chunk:表示 webpack 内部构建模块的块,通过一个入口模块就是一个 chunk,一个 chunk 中包含多个模块;
- chunk id:表示 chunk 的唯一编号;开发环境下,和 chunkname 保持一致;生产环境下,则是一个从 0 开始的数字进行编号;
- chunkname:表示 chunk 名称,默认情况是入口模块的文件名称,该值可在配置文件中配置;
- bundle:chunk 最终生成的资源清单,清单中的每一项就是一个 bundle,一个 chunk 通过打包之后可能会创建多个文件,可理解成 bundle 是最终生成的文件;
- chunkhash:表示一个 chunk 生成的资源清单内容联合生成的 hash 值;
|