webpack5 基础配置(4上)模块化原理commonjs esmodule原理。

Mode配置

之前我们打包的时候一直报错,mode属性没有设置。看下基本配置
在这里插入图片描述在这里插入图片描述
mode错误
在这里插入图片描述
在官网这里可以查到相关信息。
mode可以有三个取值,development production(默认) none
我们默认是设置为production,生产模式,顾名思义要上线了,为了性能优化,要压缩,所以webpack会进行丑化。
当我们设置为development时,会开发模式,开发模式暂时不上线所以无需丑化。
在这里插入图片描述
打包后
在这里插入图片描述
可以看到就是正常的js文件没有被压缩过。
在这里插入图片描述
这三个取值的含义以及不同取值的结果
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
每个取值其实都做了很多事情,目前只需了解他是干嘛的,还不用关系里面的具体。

模块化原理

webpack允许我们使用各种各样的模块化,如ES MODULE(ES6) COMMONJS(node)等
但浏览器默认不支持commonjs,es6模块化有些旧的浏览器也不支持。但是webpack里面我们可以随便写。那么webpack怎么支持模块化呢?

我们研究四个原理:

Commonjs模块化实现原理

ES Moduls实现原理

commnjs加载ES module的原理(es module导出commonjs导入)

es module加载commonjs的原理

1 commonjs模块化实现原理

在这里插入图片描述
在这里插入图片描述
代码很简单,方便理解。
在这里插入图片描述
可以看到很多代码很杂,把devtool设位source-map设置就好,后期再具体再了解其用途在这里插入图片描述
在这里插入图片描述
可以看到代码已经整洁多了。
在这里插入图片描述
再把注释删掉,可以看到已经很整齐了。
接着来看下代码。立即执行函数
在这里插入图片描述

在这里插入图片描述
这里放着的使我们得以一个个模块,因为现在只有一个模块,所以只有一个值。
在这里插入图片描述

再定义一个对象作为模块的缓存,如果加载过的就去缓存的值。
然后定义一个函数,当我们加载模块,就是从模块导出的东西取取值的时候,就通过这个函数的,
在这里插入图片描述
最后一个
在这里插入图片描述
这其实也是立即执行函数,可以看到我们的执行的代码实在这面的,可以看出也是通过require引入,只不过用的是webpack自己定义的函数引入。
现在看不懂没关系,理一下逻辑。
运行代码时,执行,在这里插入图片描述
传入路劲,在这里插入图片描述
走到我们自定i的函数,判断是否有缓存,有的话直接返回缓存的exprorts,
在这里插入图片描述
没有的话,放入缓存之中,定义为一个对象。然后赋值给module。最后
在这里插入图片描述
在这里插入图片描述
可以很明显看到直接调用了一开始创建用来放模块的对象。然后通过路径找到该函数,然后将module传进去。后面两个干嘛呢,刚我们的文件引用一个模块,然后里面又引用一个模块的话,这两个就有用了。现在只有一个暂时不用管他。
所以现在就相当于
在这里插入图片描述
执行了这个函数,值为{exports: {}}
然后给他赋值,赋的值
在这里插入图片描述

也就是说我们现在的module里的exports已经是这个函数了。在这里插入图片描述
然后return回去,在这里插入图片描述
然后传给num,再执行,
这样就完成模块化了。

捋一下思路,webpack帮助我们对commonjs的模块化导出,打包成一个Bundl.js文件,她做了什么事呢?首先生成一个对象,这个对象有几个属性,属性名就是我们的模块路劲,属性值是什么呢?就是我们导出的东西,可能是一个函数也可能是一个值。第二步,内部定义一个对象,这个对象存放着所有加载过的模块的缓存。第三步,内部定义一个函数,这个函数就是用来处理我们记载模块的。第四步,就是使用立即指向函数,通过第三步定义的函数,取到我们实际上导出来的值或者函数,然后再直接调用。

关键就是这个第三步,webpack会把路径传进去,然后通过这个路劲,先看缓存有没有值,没有的话,直接加入缓存去,然后再定义一个module对象,里面有个export属性,最后再通过我们第一步创建的对象,去拿到我们对应的值,这个值接受一个参数Module,就是我们顶一个那个Module对象传进去,然后通过给module.exports赋值,就把我们导出的函数赋值到上面,然后再return回去。第四步拿到函数返回来的值后,就立即执行调用,达到一个模块化的效果。第四步还可以传入两个参数,module.exports和第三步的函数,为的就是当引入的模块内部还有引入其他模块时,可以做处理,现在只有一层,所以姑且不管。

模块化其实也就是为了防止命名空间错乱,这里面的底层思想主要也是运用了函数作用域,实现了类似于模块化得效果。


在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
大体流程就是这样,可以自己去看看,很简单。

es module

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
代码有点多,但其实逻辑差不多,一步一步看。
第一步,还是一个对象。用路劲作为属性名,
在这里插入图片描述
第二步,缓存,看到Cache就知道了是个缓存。
在这里插入图片描述
第三步 加载模块的实现,跟common.js一摸一样
在这里插入图片描述
第四步,立即执行函数。这个执行函数是给我们第三步的执行函数添加一个属性r,这个r就是一个函数。这个d我们猜想就是判断是esModule还是module,因为他给我们的exports添加了属性。值设位_esModule或者symbol.toStringTag,值为Module。所以这个r函数就是Module和__esModule。
在这里插入图片描述
第五步
开始执行代码了。
在这里插入图片描述
先调用r函数,给我们的第一部创建的对象做标记,证明是_esmodule。
在这里插入图片描述

然后调用我们的第三步的函数来加载模块。
在这里插入图片描述
然后又会调用第一步的对象里面的函数
在这里插入图片描述
这时候里面的操作注意了,跟之前的不太一样,
在这里插入图片描述
这时候的module.export就是上图那样然后被第三部的函数return回去。在这里插入图片描述
拿到后调用exprots里面的default属性的值,也就是我们导出来的函数,然后执行。
里面用到了(0,fun)(a,b)其实这个跟直接fun(a,b)效果一样的。

捋一下思路,esModule与commonjs类似,但是多了一个r函数,这个函数是用来标记对象里面的一个属性,标记是否是__esModule。其他步骤与commonjs类似。

但其实我们导出了一个所以webpack默认给我们的exports对象加了个default属性,那要是两个呢?

在这里插入图片描述
在这里插入图片描述
打包后
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以看到,其实只多了第三幅图
在这里插入图片描述
多了这个d函数,跟这个o函数。先看看o函数
在这里插入图片描述
obj去调用这个hasOwnProperty,然后判断Porps是不是自身的属性。
再看看D
在这里插入图片描述
d做的事情稍微复杂一点,但仔细看,d就是遍历第二个参数,判断条件就可以看出来,是判断属性是不是自身的,或者是exports上面没有的,才会继续往下走。
往下走干嘛呢,get?似曾相识啊,这不是做代理吗。给exports对象加上key属性,然后取出的值却是definiton[key]。典型做代理呀。这个其实就是在exprots上面设置属性key,然后外面拿到这个值的真实值是definition[key],也就是exports.key = definition[key]。

了解两个用法后我们再看看怎么调用。

在这里插入图片描述
然后第三部函数最后一步调用这个对象
在这里插入图片描述
在这里插入图片描述
这里的执行跟上面的也不太一样
执行完r函数,加标记,然后执行代理,第二个参数实际上就是num和Numw,写成函数形式而已,返回的其实是下面const定义的函数和值。经过d后,exports.num export.num2就有值了,因为做了代理。

在这里插入图片描述
然后第三部的函数返回module.exports对象,在这里插入图片描述

与其说是e’xpots里面有值了,不如说是做代理了。

捋一下思路 es module多个导出的时候,比一个导出多了两个函数一个是d函数,一个是o函数,o函数用来判断自身是否有属性。d函数用来给我们的exports对象做代理,让exports.xxx可以拿到我们真实导出的值。然后返回执行。

大总结 模块化的原理其实就是webpack帮助我们利用函数作用域实现了变量的命名空间范围,实现模块化。他是怎么实现的呢?首先,他创建一个对象webpack-module,这个对象的属性名是我们的文件也就是模块的路劲,值是一个函数,这个函数是用来给module的exports赋值的。(commonjs是直接赋值,esmodule是通过代理)。然后创建一个webpack-module-cache对象,这个对象主要是用来存加载过的模块的缓存。接着他自定义了一个函数webpack-require,这个函数的作用是用来加载模块的,内部实现就是根据传入的路劲,判断缓存是否有值,有则调用缓存的值,无则直接创建新的module对象,并且存入缓存,这个Module对象里面就有exports属性。然后再通过传入的路劲,去拿到第一部创建的对象webpakc-module,拿到对应的函数,上面说过该函数就是用来给exports赋值的。commonjs是直接将exports指向了我们导出了函数或者值。这时候我们的exports就有值了,然后webpack-require再return module.exports。最后使用立即执行函数,调用webpack-require来获取exports里面的值,就是我们实际导出来的函数或者值,最后直接调用。便完成了模块化。

而es_module得话,他是给webpack-require函数加了三个属性,d函数用来给exports做代理,o函数用来判断是否是自身的属性。r函数用来标记是es_module。最后调用的时候,给exports做处理时,是通过d函数里面,通过Object.defineProperty得get函数给exports做代理,使其可以通过exports.xxx来获取我们导出去得值,最后直接执行即可。es_module如果只有一个默认导出,那么只有r函数,因为直接给exports赋予了default属性使其指向导出的值。


版权声明:本文为lin_fightin原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。