index.jswebpack
export let num = 9; let def = 44; export default def;
打包后输出的文件(eval sourcemap部分删除)es6
(function(modules) { // webpackBootstrap var installedModules = {}; 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__);console.log(module) module.l = true; return module.exports; } __webpack_require__.m = modules; __webpack_require__.c = installedModules; __webpack_require__.d = function(exports, name, getter) { if(!__webpack_require__.o(exports, name)) { Object.defineProperty(exports, name, { configurable: false, enumerable: true, get: getter }); } }; __webpack_require__.r = function(exports) { Object.defineProperty(exports, '__esModule', { value: true }); }; __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_require__.p = ""; return __webpack_require__(__webpack_require__.s = "./src/index.js"); })({ "./src/index.js": (function(module, __webpack_exports__, __webpack_require__) { "use strict"; eval("__webpack_require__.r(__webpack_exports__);\n __webpack_require__.d(__webpack_exports__, \"num\", function() { return num; });\n let num = 9;\r\n let def = 44;\r\n __webpack_exports__[\"default\"] = (def);"); }) });
打包后的文件为一个自执行的函数匿名,参数为入口文件及其依赖的模块(此处没有依赖模块)web
(function(modules) { var installedModules = {}; function __webpack_require__(moduleId) { ... } __webpack_require__.m = modules; __webpack_require__.c = installedModules; __webpack_require__.d = function(){ ... } __webpack_require__.r = function(){ ... } __webpack_require__.n = function(){ ... } __webpack_require__.o = function(){ ... } __webpack_require__.p = ''; return __webpack_require__(__webpack_require__.s = "./src/index.js"); })({ "./src/index.js": (function(module, __webpack_exports__, __webpack_require__) { "use strict"; eval("..."); })
匿名函数声明了一个installedModules对象,用于缓存加载进来的模块(加载进来的模块不必定加载完成)
声明了__webpack_require__,并为其添加了一些方法和属性:m、c、d、r、n、o
m:保存传入的模块对象
c:保存缓存的模块
d:在exports对象上添加属性
r:在exports对象上添加__esModule,用于标识es6模块
n:getDefaultExport
o:判断对象上是否有某一属性json
__webpack_require__函数segmentfault
function __webpack_require__(moduleId) { //是否有缓存 if(installedModules[moduleId]) { return installedModules[moduleId].exports; } var module = installedModules[moduleId] = { i: moduleId, //模块id l: false, //模块是否已加载 exports: {} }; //加载模块 modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); module.l = true; return module.exports; }
index.js模块里的东西经过modules[moduleId].call()中加载进来,最终的module包含以下内容数组
参数promise
{ "./src/index.js": (function(module, __webpack_exports__, __webpack_require__) { //es6模块为严格模式 "use strict"; //每一个模块都被eval执行 eval("__webpack_require__.r(__webpack_exports__);\n __webpack_require__.d(__webpack_exports__, \"num\", function() { return num; });\n let num = 9;\r\n let def = 44;\r\n __webpack_exports__[\"default\"] = (def);"); /*eval中执行了如下内容 * __webpack_require__.r(__webpack_exports__); * __webpack_require__.d(__webpack_exports__, "num", function() { return num; }); * let num = 9; * let def = 44; * __webpack_exports__["default"] = def; * */ }
"./src/index.js"为文件路径也是该模块的id
eval中为经过__webpack_require__.r给export添加__esModule属性,并定义num、default属性缓存
chunk.jsapp
let def = 44; export default def;
index.js函数
import def from './chunk1.js'; export let num = 9;
打包后的文件(自执行函数体部分不变,仅展现参数部分)
{ "./src/chunk1.js": (function(module, __webpack_exports__, __webpack_require__) { "use strict"; eval("__webpack_require__.r(__webpack_exports__);\n let def = 44;\r\n __webpack_exports__[\"default\"] = (def);"); }), "./src/index.js": (function(module, __webpack_exports__, __webpack_require__) { "use strict"; eval("__webpack_require__.r(__webpack_exports__);\n __webpack_require__.d(__webpack_exports__, \"num\", function() { return num; });\n var _chunk1_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\"./src/chunk.js\");\n\r\n let num = 9;\r\n console.log(_chunk1_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"])"); }) }
index.js模块中调用__webpack_require__("./src/chunk1.js")加载chunk.js,最终installedModules以下
index.js
import chunk1 from './chunk1.js'; import chunk2 from './chunk2.js'; export let index1 = 9; console.log(chunk1); console.log(chunk2);
chunk1.js
import chunk2 from './chunk2.js'; let chunk1 = 1; export default chunk1;
chunk2.js
let chunk2 = 2; export default chunk2;
打包后的参数部分
({ "./src/chunk1.js": (function(module, __webpack_exports__, __webpack_require__) { "use strict"; eval("__webpack_require__.r(__webpack_exports__);\n var _chunk2_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\"./src/chunk2.js\");\n\r\n let chunk1 = 1;\r\n __webpack_exports__[\"default\"] = (chunk1);"); }), "./src/chunk2.js": (function(module, __webpack_exports__, __webpack_require__) { "use strict"; eval("__webpack_require__.r(__webpack_exports__);\n let chunk2 = 2;\r\n __webpack_exports__[\"default\"] = (chunk2);"); }), "./src/index.js": (function(module, __webpack_exports__, __webpack_require__) { "use strict"; eval("__webpack_require__.r(__webpack_exports__);\n __webpack_require__.d(__webpack_exports__, \"index1\", function() { return index1; });\n var _chunk1_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\"./src/chunk1.js\");\n var _chunk2_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(\"./src/chunk2.js\");\n\r let index1 = 9;\r\n console.log(_chunk1_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"]);\r\n console.log(_chunk2_js__WEBPACK_IMPORTED_MODULE_1__[\"default\"]);"); }) });
模块不会重复加载,chunk1中import chunk2.js __webpack_require__直接返回缓存中的数据
(function(modules) { ... return __webpack_require__(__webpack_require__.s = 0); })({ "./src/chunk1.js": (function(module, __webpack_exports__, __webpack_require__) { "use strict"; eval("__webpack_require__.r(__webpack_exports__);\n let chunk1 = 1;\r\n __webpack_exports__[\"default\"] = (chunk1);"); }), "./src/index.js": (function(module, __webpack_exports__, __webpack_require__) { "use strict"; eval("__webpack_require__.r(__webpack_exports__);\n __webpack_require__.d(__webpack_exports__, \"index1\", function() { return index1; });\n var _chunk1_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\"./src/chunk1.js\");\n\r\nlet index1 = 9;\r\n console.log(_chunk1_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"]);"); }), "./src/index2.js": (function(module, __webpack_exports__, __webpack_require__) { "use strict"; eval("__webpack_require__.r(__webpack_exports__);\n __webpack_require__.d(__webpack_exports__, \"index2\", function() { return index2; });\n var _chunk1_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\"./src/chunk1.js\");\n\r\nlet index2 = 66;"); }), 0: (function(module, exports, __webpack_require__) { eval("__webpack_require__(\"./src/index.js\");\n module.exports = __webpack_require__(\"./src/index2.js\");"); }) });
相比字符串入口return的再也不是index.js,而是moduleId为0的模块,在0模块中触发index、index2模块的加载并返回index2模块(数组中的最后一项)
runtimeChunk为true
index.bundle.js
(function(modules) { // install a JSONP callback for chunk loading function webpackJsonpCallback(data) { var chunkIds = data[0]; var moreModules = data[1]; var executeModules = data[2]; // add "moreModules" to the modules object, // then flag all "chunkIds" as loaded and fire callback var moduleId, chunkId, i = 0, resolves = []; for(;i < chunkIds.length; i++) { chunkId = chunkIds[i]; if(installedChunks[chunkId]) { resolves.push(installedChunks[chunkId][0]); } installedChunks[chunkId] = 0; } for(moduleId in moreModules) { if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) { modules[moduleId] = moreModules[moduleId]; } } if(parentJsonpFunction) parentJsonpFunction(data); while(resolves.length) { resolves.shift()(); } // add entry modules from loaded chunk to deferred list deferredModules.push.apply(deferredModules, executeModules || []); // run deferred modules when all chunks ready return checkDeferredModules(); }; function checkDeferredModules() { var result; for(var i = 0; i < deferredModules.length; i++) { var deferredModule = deferredModules[i]; var fulfilled = true; for(var j = 1; j < deferredModule.length; j++) { var depId = deferredModule[j]; if(installedChunks[depId] !== 0) fulfilled = false; } if(fulfilled) { deferredModules.splice(i--, 1); result = __webpack_require__(__webpack_require__.s = deferredModule[0]); } } return result; } var installedModules = {}; // object to store loaded and loading chunks // undefined = chunk not loaded, null = chunk preloaded/prefetched // Promise = chunk loading, 0 = chunk loaded var installedChunks = { "runtime~main": 0 }; // script path function function jsonpScriptSrc(chunkId) { return __webpack_require__.p + "" + chunkId + ".index.bundle.js" } var deferredModules = []; // 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_require__.m = modules; __webpack_require__.c = installedModules; __webpack_require__.d = function(exports, name, getter) { if(!__webpack_require__.o(exports, name)) { Object.defineProperty(exports, name, { configurable: false, enumerable: true, get: getter }); } }; __webpack_require__.r = function(exports) { Object.defineProperty(exports, '__esModule', { value: true }); }; __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_require__.p = ""; var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || []; var oldJsonpFunction = jsonpArray.push.bind(jsonpArray); //改写push方法,main中调用该方法 jsonpArray.push = webpackJsonpCallback; jsonpArray = jsonpArray.slice(); //main.index.bundle.js push以前jsonpArray为空 for(var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]); //保留原始的push方法,webpackJsonpCallback中经过该方法将main.inde.bundle.js中的数组添加进window["webpackJsonp"] var parentJsonpFunction = oldJsonpFunction; // run deferred modules from other chunks checkDeferredModules(); })([]);
总体为一个自执行函数,所以时参数为空,index.bundle.js中只是绑定了一些属性、方法,并未加载具体的模块。
installedModules缓存已加载的模块
installedChunks缓存chunnk,值为undefined表示模块还没有加载,null表示preloaded/prefetched,promise表示加载中,0表示已加载
webpackJsonpCallback中处理数据绑定及回调
checkDeferredModules中检测chunks的加载状况,所有loaded后调用__webpack_require__('./src/index.js')处理具体模块的加载(./src/index.js为入口模块的id)
main.index.bundle.js
(window["webpackJsonp"] = window["webpackJsonp"] || []).push([ ["main"], { "./src/chunk1.js": (function(module, __webpack_exports__, __webpack_require__) { "use strict"; eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _chunk2_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./chunk2.js */ \"./src/chunk2.js\");\n\r\nlet chunk1 = 1;\r\n/* harmony default export */ __webpack_exports__[\"default\"] = (chunk1);\n\n//# sourceURL=webpack:///./src/chunk1.js?"); }), "./src/chunk2.js": (function(module, __webpack_exports__, __webpack_require__) { "use strict"; eval("__webpack_require__.r(__webpack_exports__);\nlet chunk2 = 2;\r\n/* harmony default export */ __webpack_exports__[\"default\"] = (chunk2);\n\n//# sourceURL=webpack:///./src/chunk2.js?"); }), "./src/index.js": (function(module, __webpack_exports__, __webpack_require__) { "use strict"; eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"index1\", function() { return index1; });\n/* harmony import */ var _chunk1_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./chunk1.js */ \"./src/chunk1.js\");\n/* harmony import */ var _chunk2_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./chunk2.js */ \"./src/chunk2.js\");\n\r\n\r\nlet index1 = 9;\r\nconsole.log(_chunk1_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"]);\n\n//# sourceURL=webpack:///./src/index.js?"); }) }, [["./src/index.js","runtime~main"]] ]);
window["webpackJsonp"].push会调用webpackJsonpCallback方法
index.js
import chunk1 from './chunk1.js'; export let index1 = 9; import('./chunk2.js').then(res=>{ console.log(res); }).catch(e=>{ console.log(e) })
打包后的代码仅main.index.bundle.js的"./src/index.js"eval部分不一样
__webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, "index1", function() { return index1; }); var _chunk1_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/chunk1.js"); let index1 = 9; Promise.resolve() .then(__webpack_require__.bind(null, "./src/chunk2.js")) .then(res=>{ console.log(res); }) .catch(e=>{ console.log(e) });
import()的promise直接resolve,回调在then(__webpack_require__.bind(null, "./src/chunk2.js"))后执行