webpack是当下最流行的模块打包工具,webpack处理应用程序时候,会递归构建一个依赖关系图,其中包含应用程序的每个模块,然后将这些模块打包成一个或者多个bundle
本文使用的webpack版本是4.8.3
// src/a.js
const a = 'a module';
export default a;
// src/index.js
import a from './a'
console.log(a);
console.log('index');
执行webpack --mode development
,在dist文件夹会打包成一个打包后的main.js文件,以下是打包后的文件
/**
* 传入一个modules对象
**/
(function (modules) {
// 定义一个变量缓存模块
var installedModules = {};
// require函数
function __webpack_require__(moduleId) {
// 如果模块存在直接返回
if (installedModules[moduleId]) {
return installedModules[moduleId].exports;
}
// 创建新的模块并且缓存起来
var module = installedModules[moduleId] = {
i: moduleId,
l: false,
exports: {}
};
// 执行模块函数
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
// 标记已经加载完毕
module.l = true;
// 返回模块
return module.exports;
}
// modules对象
__webpack_require__.m = modules;
// 模块缓存对象
__webpack_require__.c = installedModules;
// define getter function for harmony exports
__webpack_require__.d = function (exports, name, getter) {
if (!__webpack_require__.o(exports, name)) {
Object.defineProperty(exports, name, {
configurable: false,
enumerable: true,
get: getter
});
}
};
// define __esModule on exports
__webpack_require__.r = function (exports) {
Object.defineProperty(exports, '__esModule', {value: true});
};
// getDefaultExport function for compatibility with non-harmony modules
__webpack_require__.n = function (module) {
var getter = module && module.__esModule ?
function getDefault() {
return module['default'];
} :
function getModuleExports() {
return module;
};
__webpack_require__.d(getter, 'a', getter);
return getter;
};
// 判断对象是否有属性
__webpack_require__.o = function (object, property) {
return Object.prototype.hasOwnProperty.call(object, property);
};
// __webpack_public_path__
__webpack_require__.p = "";
// 加载入口模块,并且返回该模块
return __webpack_require__(__webpack_require__.s = "./webpack/index.js");
})({
"./webpack/a.js": (function (module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\nconst a = 'a module';\r\n/* harmony default export */ __webpack_exports__[\"default\"] = (a);\n\n//# sourceURL=webpack:///./webpack/a.js?");
}),
"./webpack/index.js": (function (module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _a__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./a */ \"./webpack/a.js\");\n\r\nconsole.log(_a__WEBPACK_IMPORTED_MODULE_0__[\"default\"]);\r\nconsole.log('index');\n\n//# sourceURL=webpack:///./webpack/index.js?");
})
});
从去除注释后的代码看出,模块打包后是一个立即执行函数,传入的参数为一个对象
{
"./webpack/a.js": function (module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
const a = 'a module';
__webpack_exports__["default"] = (a);
},
"./webpack/index.js": function (module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
// 这里找到了依赖模块./webpack/a.js,执行模块./webpack/a.js的代码
var _a__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./webpack/a.js");
console.log(_a__WEBPACK_IMPORTED_MODULE_0__["default"]);
console.log('index');
}
}
在IIFE函数最后return的时候会去调用__webpack_require__函数,传入的是入口文件./webpack/index.js这个就是作为模块的id,然后__webpack_require__
就会去执行下面入口模块的代码
/**
* @module 模块对象 { i: moduleId, l: false, exports: {} }
* @__webpack__exports__ 相当于 module.exports 一个空的对象
* @__webpack__require__ require函数
*/
(function (module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
// 这里找到了依赖模块./webpack/a.js,执行模块./webpack/a.js的代码
var _a__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./webpack/a.js");
console.log(_a__WEBPACK_IMPORTED_MODULE_0__["default"]);
console.log('index');
})
接下来index.js依赖于模块a,继续执行./webpack/a.js的代码,返回以下新的对象,用变量_a__WEBPACK_IMPORTED_MODULE_0__
保存起来,a.js执行后返回的对象的结构为
{
i: "",
l: true,
exports: {
default: 'a module', // 这个例子返回的就是一个常量
__esModule: true
}
}
总结
- webpack会把所有的模块用一个对象来表示,类似这种格式
{ moduleId: function(module, module.exports, require) { // 模块对应的代码 }; }
,传入到立即执行函数中 - 从入口文件开始执行代码,遇到有模块依赖的时候,会去缓存对象
installedModules
里面查找依赖的模块对象来执行,如果没有找到就执行模块的代码并把依赖的模块缓存在installedModules
对象中