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"))後執行