webpack模块机制浅析【一】

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执行)

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏WindCoder

MyBatis传入参数为集合 list 数组 map写法

这几天需要or和拼接in的特定查询条件来做查询,想看看mybatis是否可以通过传递list集合实现,于是找到了他的foreach标签。

5K20
来自专栏程序生活

Python 过滤字母和数字实例1实例 2实例 3

34420
来自专栏书山有路勤为径

哈希表基础知识

哈希表(Hash table,也叫散列表),是根据关键字值(key)直接进行访问的数据结构,它通过把关键字值映射到表中一个位置(数组下标)来直接访问,以加快查找...

9210
来自专栏ShaoYL

OC语言Block 续

14490
来自专栏Ryan Miao

MongoDB-基础-条件操作符

1.一些解释 less than         :  比..少  lt greater than      :  比..多  gt equals       ...

31160
来自专栏闵开慧

java概念1

public static void main(String[] args) {//其中[]也可以写在args后面,args也可以随便写成其他字母,例如asd...

368110
来自专栏听Allen瞎扯淡

Integer的highestOneBit方法源码解析

在读HashMap源码的时候,遇到了Integer的highestOneBit静态方法不是太理解,所以就读了一下源码,这里记录一下。

39110
来自专栏Samego开发资源

学习C语言基础知识 | 实践篇

27430
来自专栏Coding迪斯尼

自制Monkey编程语言编译器:增加数组操作API和Mapsh数据类型

13730
来自专栏Java开发者杂谈

java如何获取一个对象的大小

When---什么时候需要知道对象的内存大小 在内存足够用的情况下我们是不需要考虑java中一个对象所占内存大小的。但当一个系统的内存有限,或者某块程序代码允许...

1.6K70

扫码关注云+社区

领取腾讯云代金券