You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
var installedModules = {}; // The require function
function __webpack_require__(moduleId) {
// Check if module is in cache
if (installedModules[moduleId]) {
return installedModules[moduleId].exports;
} // Create a new module (and put it into the cache)
var module = (installedModules[moduleId] = {
i: moduleId,
l: false,
exports: {}
}); // Execute the module function
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
// Flag the module as loaded
module.l = true; // Return the exports of the module
return module.exports;
}
前言
我们平时用webpack来打包, 对于使用
以上两种完全不同的模块引入方式, 完全是没有区别, 如果模块本身支持, 那么是可以互换的, 怎么加载取决该文件的导出方式, 但无论我们怎么写,在webpack打包之后,都可以很好的运行.
这当然要感谢webpack, 因为它对我们的混杂的模块化代码做了兼容,
所以, 下面来了解它的具体的实现过程.
怎么区分ES6模块还是CommonJs的模块?
要能兼容不同的模块引入, 那么必须得要先识别不同的模块引入方式,
在webpack开始解析代码的时候, 有一个必要的步骤是, 生成AST语法树.在这里, 通过AST树中的
type
判断是否ExportDefaultDeclaration
, 就可以判断是否ES6的模块加载的了.关于AST的更多信息详情,点击这里打包出来的代码默认是和
runtime
的代码一起的, 什么是runtime
的代码? 也就是定义了__webpack_require__
这样的必要的加载模块的函数的代码.打包后怎么引入模块
而我们们引入的模块是通过参数的形式传进去的, 像这样子.
打包后的ES6模块代码
那问题来了, 那关于ES6打包和CommonJs的打包转化后的代码会变成什么样子?
可以看到,打包后的代码变化很大, 首先因为需要兼容2种不同的打包方式, 如果是方法可以重写(像CommonJs的
module.export/require
可以通过自动module变量来起作用), 但是export/import
关键字不能重写, 所以需要把原生的写法转为使用自己的模块加载方法__webpack_require__
. 所以就变成了这样了其次, 为了识别是ES6的模块加载方式, 在需要在导出该对象的时候, 给该导出的对象
__webpack_exports__
添加__esModule=true
标识.如果ES6的单个属性导出的话,则是这样子
也就是在
__webpack_exports__
上定义属性, 在模块引入的时候, 发现是ES6的模块, 那么直接返回__webpack_exports__
的具体属性.注意的是, 这里是先利用闭包定义了一个局部变量, 然后利用函数导出这个局部变量的引用. 也就是说ES6的属性导出和模块导出是一个引用.
打包后的CommonJs的模块
这里就不需要重写原生代码了, 挟持module就可以.
导出模块引入方式
模块的引入是用
__webpack_require__
方法, 这是一个同步引入模块的方式, 利用installedModules
缓存导出的对象exports
.异步模块引入的方式
require是webpack传入的一个变量, 可以进行异步组件的引入, webpack对于以上的代码的打包, 转化成如下
打包后的异步加载加载的入口是
__webpack_require__.e(0)
的形式, 那么自然异步组件的内容变动, 理论上是不会影响runtime
的环境代码的(如果指纹是用contenthash的话), 但是因为异步代码对应的hash是写在runtime
里面的,所以 很难做到runtime
和异步组件的完全不受影响.而
require.ensure
方法的实现, 也就是新建一个script, 加载异步组件的内容webpack 的代码分割把
bar.js
的代码打包成了0.8b8e7b45f7069f5599d7.bundle.js
, 加载的时使用下标的形式加载__webpack_require__.e(0)
,__webpack_require__.e
则是requireEnsure
, 加载异步代码的, 使用下标加载 , 识别对应下标的hash,是使用jsonpScriptSrc
函数,这个函数在每次异步组件更新的时候(如果指纹是用contenthash的话),都会随异步组件的内容变动.
总结
到这里, 其实很多加载方面的东西都很清晰了,
The text was updated successfully, but these errors were encountered: