webpack模块机制浅析【一】
今天看了看webpack打包后的代码,所以就去分析了下代码的运行机制。
下面这段代码是webpack打包后的最基本的形式,可以说是【骨架】
(function(root,fn){
if(typeof exports ==='object'&&typeof module === 'object'){
module.exports = fn();//exports和module同时存在,说明时在node的CommonJs规范下,这个时候使用module.exports来导出模块,fn函数执行后是返回一个模块
}else if(typeof define === 'function' && define.amd){
define([],fn);//当exports和module不同时存在时,先判断define和define.amd是否存在;如果存在表明在AMD规范下,所以就使用define函数"包裹"一下fn函数,以此来声明一个AMD规范下的模块
}else if(typeof exports === 'object'){
exports['packname'] = fn();//packname表示的包名,exports据说是module.exports的引用,但是我不明白module不存在何来exports,求网友解答,不清楚什么时候代码能够执行到这里?
}else {
root['packname'] = fn();//这个应该是如果上面的情况都不存在那就把它绑定在当前执行环境的"根节点",如在浏览器下就绑定在window上;
}
})(this,function(){//this丢进去变成了root,后面这个function丢进去就是fn
return (function(modules){//modules是参数丢进来的函数数组
var installed = {};//用来装载已声明模块
function _webpack_require_(moduleId){//webpack的包获取函数,使用这个函数去检索前面传进来的modules函数数组,从而解锁出每一个函数数组中的元素(也可以说是模块),每一个数组元素一般都是会存在闭包以隔离作用域,每一个元素中会使用module.exports来作为输出寄托对象。
if(installed[moduleId]){//moduleId其实就是modules数组的索引
return installed[moduleId].exports;//如果存在说明之前函数执行过
}
var module = installed[moduleId] = {//可以说是缓存模块
exports:{},//这个会使用下面的call函数来改变。
id:moduleId,
loaded:false
}
modules[moduleId].call(module.exports,module,module.exports,_webpack_require_)
//上面一句中,其实是执行modules[moduleId]()函数,只不过函数this指向了module.exports(也就是this)
//还是上面一句解释(因为重要啊):第二个参数module其实是一个【地址引用】,只要执行函数在函数中对这个module做了更改,那么最开始的module就做了更改,这也是为什么后面的函数数组中的函数都把方法和变量都绑定在module.exports上面的原因
module.loaded = true;//可以不管
return module.exports;//这个很重要,这个时候module.exports已经被上面的call函数装饰过了。在经过无数个函数的洗礼之后,这个module.exports会逐渐成长为包含各种变量和方法的【大对象】,反正就是个对象,最后return丢给外层的module.exports或者this或者丢给AMD的define可以。
}
_webpack_require_.m = modules;//这个先可以不管
_webpack_require_.c = installed;//缓存,先不管
_webpack_require_.p = '';//先不管
return _webpack_require_(0);//这个是函数执行的入口,相当于执行modules[0]函数,可以在modules的第一个函数中再去调用其他函数
})([//注意这是一个函数数组,里面都是函数,也可以理解为模块
function(module,exports,_webpack_require_){
// console.log('hi');
console.log(this);//如果在下没猜错的话,下面几个函数中的this输出都是{},也就是_webpack_require_一开始定义modules下的exports(初始化为{}),对吧?
module.exports = _webpack_require_(1);
},
function(module,exports,_webpack_require_){
console.log(this);//{}
let str = _webpack_require_(2);//调用其他模块
let isType = _webpack_require_(3);
module.exports = {age:18,str:str,isType:isType};
},
function(module,exports,_webpack_require_){
console.log(this);//{}
module.exports = '你好'
},
function(module,exports,_webpack_require_){
console.log(this);//{}
module.exports = function(type){
return function(obj){//返回一个函数
return Object.prototype.toString.call(obj) === "[object "+type+"]";//判断变量类型的黑科技
}
}
}
]);
}) /*********/
if(typeof module =='object' && typeof exports == 'object'){
console.log(module.exports);//{ age: 18, str: '你好', isType: [Function] }
var isArray = module.exports.isType("Array");//返回的是一个函数
console.log(isArray([1]));//true
console.log(isArray('1'));//false
console.log(isArray(1));//false
}else if(typeof define == 'function'){
console.log('AMD');
}else{
console.log(this);
var isArray = this.isType("Array");//返回的是一个函数
console.log(isArray([1]));//true
console.log(isArray('1'));//false
console.log(isArray(1));//false
}
理解这个对于理解别人源码会有帮助,如果你不懒,我觉得你应该会把这段代码执行一下(用node执行)