扣webpack的理解
我们直接看一下webpack加载器伪代码
var d = {}; // 缓存模块
// 功能模块
var e = {
0: function(module, exports, require) {
exports.sayHello = function() {
console.log("Hello, world!");
};
},
1: function(module, exports, require) {
var hello = require(0);
hello.sayHello(); // 执行模块 0 中的 `sayHello` 方法
}
};
function a(f) { // 加载器
if (d[f]) // 如果模块已缓存,返回缓存中的导出对象
return d[f].exports;
// 如果模块未被缓存,初始化缓存对象
var c = d[f] = {
i: f, // 模块的标识符(ID)
l: !1, // 加载状态(false 表示未加载)
exports: {} // 初始化导出对象
};
// 执行模块的定义函数,设置上下文为exports,并传递 `exports`、`module` 和 `require`
e[f].call(c.exports, c, c.exports, a);
// 标记模块为已加载
c.l = !0;
// 返回模块的导出对象
return c.exports;
}
a.e = "asdasd"
console.log(a.e,a);
/*
输出 asdasd [Function: a] { e: 'asdasd' }
a可以简单理解变成了类,a()是构造函数
*/
a(1) // 输出Hello, world!
执行流程
- 调用a(1)
- 使用到了e内的0方法,使用加载器来获取
- 发现d缓存中不存在,创建一个对象,同时给d[f]和c赋值过去
- 再次通过e[f].call调用e[0]函数,将上下文的变成{},传递模块和导出以及加载器
- 0函数将空{}添加一个sayHello函数
- 加载器返回在require(0)运行时创建的c变量的exports
- hello变量接收,实际hello变为了 { sayHello: function() }
- 调用sayHello变量
结论
因此我们扣模块时候将加载器部分赋值一个变量,就可以操控整个对象包括有关加载器,然后调用缺啥补啥即可
// 功能模块
var e = {
0: function(module, exports, require) {
exports.sayHello = function() {
console.log("Hello, world!");
};
},
1: function(module, exports, require) {
var hello = require(0);
hello.sayHello(); // 执行模块 0 中的 `sayHello` 方法
}
};
let loader = {}
// 真实环境中下面{}内为单独文件,这里用{}分开让他与外部互不影响
{
function a(f) {
if (d[f])
return d[f].exports;
var c = d[f] = {
i: f,
l: !1,
exports: {}
};
e[f].call(c.exports, c, c.exports, a);
c.l = !0;
return c.exports;
}
loader = a; // 直接把加载器赋值到loader上
var d = {}; // 缓存模块
a.e = "asdasd" // a上的方法或值
}
console.log(loader.e); // 输出asdasd
loader(1) //输出Hello, world!
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。