Webpack——编译结果简化分析本文将以两个基础模块为例,模拟一个简化的webpack编译结果,将编译结果中的每个部分
📚Webpack作为现代前端开发中的核心构建工具,以其强大的模块打包能力而广受欢迎。然而,对于初学者而言,编译后的代码往往是复杂且难以理解的。为了更好地学习Webpack的工作原理,本文将从一个实际的角度出发,对编译结果进行简化分析。
本文将以两个基础模块为例,模拟一个简化的编译结果,将编译结果中的每个部分逐一拆解,用浅显的语言解释其作用和意义。
🌟通过本文,你将能够:
- 识别编译后代码的关键组成部分。
- 学会如何阅读和分析Webpack的输出结果。
下面,正文开始
一、示例的两个模块
src下有两个模块
// a.js
console.log("module a")
module.exports = "a";
// index.js
console.log("index module")
var a = require("./a")
a.abc();
console.log(a)
二、编译结果的结构
npm run dev
后,得到dist/main.js
代码太长,收起来看一下结构
这是一个立即执行函数
后面的({...})是立即执行函数的参数,是一个对象字面量, 在模块化的场景中,这通常代表了一组模块的定义或者依赖关系。
- 这种结构通常用于实现模块化加载器(如类似于Webpack、Rollup等打包工具生成的代码),它们会将模块打包成一个函数或对象,然后作为参数传递给这个立即执行的函数。
- 在函数内部,可以通过处理
modules
对象来加载和管理模块,实现模块化加载和依赖管理的功能。
示例
(function(modules) {
function __webpack_require__(moduleId) {
return ...;
}
return __webpack_require__(module0);
})({
module0: function(module, exports, __webpack_require__) {
console.log('Hello World');
},
module1: function(module, exports, __webpack_require__) {
console.log('Another Module');
}
});
展开,
立即执行函数的参数({...})对应的是:
立即执行函数对应的是:
三、简化编译结果
1. 参数内容
(function(modules){
})({//该对象保存了所有的模块,以及模块对应的代码
"./src/a.js": function (module, exports) {
console.log("module a")
module.exports = "a";
},
"./src/index.js": function (module, exports, require) {
console.log("index module")
var a = require("./src/a.js")
console.log("a")
}
})
把对象作为字面量传入立即执行函数,避免污染全局变量,同时把模块构建好。
立即执行函数的modules传入所有模块
2. 函数体
(function(modules){
//require函数相当于是运行一个模块,得到模块导出结果
function require(moduleId) { //moduleId就是模块的路径
var func = modules[moduleId]; //得到该模块对应的函数
var module = {
exports: {}
}
func(module, module.exports, require); //运行模块
var result = module.exports; //得到模块导出的结果
return result;
}
//执行入口模块
require("./src/index.js"); //require函数相当于是运行一个模块,得到模块导出结果
})
立即执行函数里要传入require函数,因为模块代码里引用其他模块,require函数相当于是运行一个模块,得到模块导出结果
3. 进一步完善:增加缓存
eval
简化后的模拟编译结果与真实的编译结果作对比,基本一致,但发现模块的内容放进了eval里
为什么把模块放入eval里? 与浏览器有关,为了方便调试
使用eval示例:
使用刚才简化的编译后的代码,不使用eval包裹模块
给index.js加入一句会报错的代码
点击进入,可以看到:
如果不写在eval里,只能在main文件里调试。
改为eval包裹
此时查看报错,可以看到,右边显示了位置
点击进入源代码
浏览器支持eval里的代码在另一个环境执行。eval里的代码是放在另一个环境里去执行的,因此调试时看不到其他代码的干扰。
显示位置的文字是可以修改的,在eval后面的 //# sourceURL=webpack:///./src/index.js
修改即可。
比如改为//# sourceURL=webpack:///./src/indexOOO.js
报错位置的显示为
注:生产环境相比于开发环境,会进一步压缩,变量名简化,换行取消等
扩展:
为什么要使用函数来包裹模块
- 作用域隔离: 每个模块都有自己的私有作用域,防止变量名冲突。
- 模块化管理: 模拟 Node.js 的模块系统,使得代码更符合 CommonJS 标准。
- 优化和扩展: 便于实现各种优化技术和插件机制,如代码分割、缓存和热模块替换等。
转载自:https://juejin.cn/post/7380200984058707994