Open zp1112 opened 6 years ago
使用webpack,最直观的可以看到打包后的结果是webpack将所有文件整合生成了一个bundle.js文件,然后往html文件里面一塞,就完事了。这么神奇,那么探索的入口就在于这个bundle.js(也没有别的入口了。。。)
由于浏览器没法直接执行CommonJS规范的模块,而webpack通过对js代码的解析和抽象,将入口文件转换成立即执行函数,将依赖模块包裹成函数,实现了模块化编程。
我们查看bundle的源码可以发现它是一个立即执行函数,这个函数的参数是modules,即webpack经过某种神力(其实是js代码解析工具,将js代码抽象成语法树(AST),然后深度遍历出一个模块依赖关系对象)整理出来的一个模块数组。数组的每个元素,都是一个函数,函数参数是module, exports, webpack_require。这个函数包裹的函数体就是每个模块的代码,其中参数module和exports是webpack自己实现的一套模块机制,类似于commonjs原理,这里使用webpack的模块机制将市面上各种AMD,CMD,commonjs等模块加载机制统一成webpack的这套机制。
module
exports
webpack_require
webpack_require是webpack核心的模块加载函数,它通过模块id(遍历生成的),找到对应模块,执行并将模块的导出对象,变成module模块的exports对象的属性。其中这个module就是新创建的模块,如果该模块已创建过了,则使用缓存installedModule。
经过以上简单分析,可以得到如下简单的代码:
(function(modules){ function webpack_require(moduleId) { // 缓存模块 const installedModule = {}; if (installedModule[moduleId]) { return installedModule[moduleId].exports; } // 新建模块 const module = { id: moduleId, exports: {} } // 调用模块函数,执行里面的源码,将到处对象挂载到新建模块的exports上面,内部依赖递归调用 // webpack_require函数 modules[moduleId].call(module.exports, module, module.exports, webpack_require); // 加入缓存 installedModule[moduleId] = module; // 返回导出对象 return module.exports; } return webpack_require(0); // 执行入口文件,modules数组的第一个元素 })([function(module, exports, webpack_require) { // 0 app.js入口文件 console.log(333) const moduleA = webpack_require(1); // 执行依赖文件,modules数组的第二个元素 const b = moduleA.a * 2; console.log(b); }, function(module, exports, webpack_require) { // 1 a.js let a = 1; function aa() { console.log(111) }; module.exports = { a, aa } }])
boom!!!,执行一下这段代码,可以看到正常打出333 2,执行了入口文件并执行了依赖文件。
333 2
其中 a.js和app.js都被一个函数包裹起来了,这个函数实现了将模块源码里面的commonjs语法或者其他模块加载语法导出的属性(commonjs原生支持,其他语法用相应的loader解析),转换成参数module和exports上面的属性导出。
function(module, exports, webpack_require) { // 模块代码 }
那么代码分割,按需引入的模块是如何加载的呢,自然不能使用直接call执行函数了,webpack中定义了专门的方法,webpack_require.e函数将代码通过script标签的形式动态加载,加载完成后,调用回调函数webpackJsonp执行模块代码。模拟了类似jsonp原理。
理解到这先。。。
bundle.js
使用webpack,最直观的可以看到打包后的结果是webpack将所有文件整合生成了一个bundle.js文件,然后往html文件里面一塞,就完事了。这么神奇,那么探索的入口就在于这个bundle.js(也没有别的入口了。。。)
由于浏览器没法直接执行CommonJS规范的模块,而webpack通过对js代码的解析和抽象,将入口文件转换成立即执行函数,将依赖模块包裹成函数,实现了模块化编程。
我们查看bundle的源码可以发现它是一个立即执行函数,这个函数的参数是modules,即webpack经过某种神力(其实是js代码解析工具,将js代码抽象成语法树(AST),然后深度遍历出一个模块依赖关系对象)整理出来的一个模块数组。数组的每个元素,都是一个函数,函数参数是
module
,exports
,webpack_require
。这个函数包裹的函数体就是每个模块的代码,其中参数module和exports是webpack自己实现的一套模块机制,类似于commonjs原理,这里使用webpack的模块机制将市面上各种AMD,CMD,commonjs等模块加载机制统一成webpack的这套机制。webpack_require
是webpack核心的模块加载函数,它通过模块id(遍历生成的),找到对应模块,执行并将模块的导出对象,变成module模块的exports对象的属性。其中这个module就是新创建的模块,如果该模块已创建过了,则使用缓存installedModule。经过以上简单分析,可以得到如下简单的代码:
boom!!!,执行一下这段代码,可以看到正常打出
333 2
,执行了入口文件并执行了依赖文件。其中 a.js和app.js都被一个函数包裹起来了,这个函数实现了将模块源码里面的commonjs语法或者其他模块加载语法导出的属性(commonjs原生支持,其他语法用相应的loader解析),转换成参数module和exports上面的属性导出。
chunk代码分割
那么代码分割,按需引入的模块是如何加载的呢,自然不能使用直接call执行函数了,webpack中定义了专门的方法,webpack_require.e函数将代码通过script标签的形式动态加载,加载完成后,调用回调函数webpackJsonp执行模块代码。模拟了类似jsonp原理。
理解到这先。。。