webpack 模块化 原理
参考:https://segmentfault.com/a/1190000010349749
一、webpack模块打包后的结构:【每个模块 都加了圆括号,但 不是 立即执行 函数】
补充介绍【圆括号的作用】:js中 数组 的 项 不能是语句,可以是表达式。js 的函数分 声明式函数 和 表达式函数。 下面的 模块 函数 不加 圆括号其实也是 对的。js引擎会自动把它处理成 函数表达式的。
webpack 的作者 加上这个 圆括号的作用,可能是 为了 消除 javascript引擎识别函数表达式和函数声明的歧义,告诉javascript引擎这是一个函数表达式,不是函数声明。
(function (modules) { // 所有的模块以数组参数 传递进来 /* 省略函数内容,这里的函数 都 webpack 自己的处理函数 */ }) ([ (function (module, exports, __webpack_require__) { /* 模块index.js的代码 */ }), (function (module, exports, __webpack_require__) { /* 模块bar.js的代码 */ }) ]);
这个结构 用的 就是 js 的自执行函数的结构:
(function (modules) { /* 省略函数内容,这里的函数 都 webpack 自己的处理函数 */ })(); /* 子执行函数 传入参数 */
二、webpack自己内部函数 实现逻辑:
// 1、模块缓存对象 var installedModules = {}; // 2、webpack实现的require function __webpack_require__(moduleId) { // 3、判断是否已缓存模块 if(installedModules[moduleId]) { return installedModules[moduleId].exports; } // 4、缓存模块 var module = installedModules[moduleId] = { i: moduleId, l: false, exports: {} }; // 5、调用模块函数 modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); // 6、标记模块为已加载 module.l = true; // 7、返回module.exports return module.exports; } // 8、require第一个模块 return __webpack_require__(__webpack_require__.s = 0);
1、 没有模块有没有加载过都有标记的,已经加载过的模块 就不会加载。
2、module.exports 是 用来缓存 模块导出的内容的。如果模块有导出内容就会 存 在这里。
3、call 是用来解决 模块中 this 指向问题的,模块化肯定要考虑 this 指向的问题,所以上面用call解决【亲测,如果模块中没有使用 this,不用call也可以正常运行】。