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也可以正常运行】。