webpack-bundle.js原理
阿新 • • 發佈:2019-01-14
bundle.js
原始碼
//a.js
import { log } from './b.js'
log('hello')
//b.js
export const log = function (m) {
console.log(m)
}
export const error = function (m) {
console.error(m)
}
自執行函式
//其中 module0 和 module1 是我們的 a 和 b兩個模組,不過也被一個函式包起來了。這段程式碼會把我們的模組放入一個數組,傳給自執行函式,他來負責呼叫模組。 (function(modules) { var installedModules = {}; function __webpack_require__(moduleId) {} // Load entry module and return exports return __webpack_require__(__webpack_require__.s = 0); }) (function (modules) {})([module0, module1])
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; }
require靜態方法
__webpack_require__.m = modules;//獲取模組列表 __webpack_require__.c = installedModules; //獲取快取模組列表 __webpack_require__.d = function(exports, name, getter) {//定義一個getter方法 if(!__webpack_require__.o(exports, name)) { Object.defineProperty(exports, name, { enumerable: true, get: getter }); } } //如果此exports物件__esModule屬性為true的話,表示這是一個es6的模組 __webpack_require__.r = function(exports) { if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); } Object.defineProperty(exports, '__esModule', { value: true }); } /** * 建立一個偽名稱空間物件 * mode & 1 value 是一個模組id,require(value)載入模組 * mode & 8 將value的所有屬性合併到ns物件當中 * mode & 4 返回已經是nsobject到value * mode & 8 | 1 繫結getter方法 */ __webpack_require__.t = function(value, mode) { if(mode & 1) value = __webpack_require__(value); if(mode & 8) return value; if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; var ns = Object.create(null); __webpack_require__.r(ns); Object.defineProperty(ns, 'default', { enumerable: true, value: value }); if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); return ns; } //相容模組物件,給模組物件繫結getter方法 __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; } //Object.prototype.hasOwnProperty.call判斷物件有沒有某個屬性 __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; // __webpack_public_path__ __webpack_require__.p = "";
依賴關係
因為webpack從entry開始,對每一個 module 都進行處理,碰到 require 之後就跳入到對應的 module 的處理,也就是遞迴的對這顆依賴樹進行處理,這是典型的深度優先遍歷的遞迴解法,而且是先序優先遍歷。處理的過程是這樣的
處理 main.js,記錄入口 [main]
碰到 require(a),記錄 [main, a]
進入到 a 模組,碰到語句 require(c), 記錄下來 [main, a, c]
同理碰到 require(d),記錄下來 [main, a, c, d]
返回到 main.js,下一句是 require('b'),記錄下來 [main, a, c, d, b]
進入模組 b,碰到語句 require(e),記錄下來[main, a, c, d, b, e]
返回,結束
打包後代碼
(function(modules){
/**
* {
* "./src/b.js":fn(...),
* "./src/test.js":fn(...)
* }
*/
//快取模組
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__);
//將模組標記為已載入
module.l = true;
//返回模組的匯出
return module.exports;
}
//掛在靜態方法
__webpack_require__.m = modules;//獲取模組列表
__webpack_require__.c = installedModules; //獲取快取模組列表
/**
let obj={};
let age='age';
function getter() {
return 9;
}
Object.defineProperty(obj,age,{enumerable: true,get: getter});
console.log(obj.age)
*/
//檢查exports物件上有沒有掛載name屬性,沒有就掛載一個
__webpack_require__.d = function(exports, name, getter) {//定義一個getter方法
if(!__webpack_require__.o(exports, name)) {
Object.defineProperty(exports, name, { enumerable: true, get: getter });
}
}
/**
* 物件的Symbol.toStringTag屬性,指向一個方法
* 在該物件上面呼叫Object.prototype.toString方法時,如果這個屬性存在,它的返回值會出現在toString方法返回的字串之中,表示物件的型別
* 也就是說,這個屬性可以用來定製[object Object]或[object Array]中object後面的那個字串
* ({[Symbol.toStringTag]: 'Foo'}.toString()) "[object Foo]"
*/
// define __esModule on exports 在匯出物件上定義__esModule屬性
//如果此exports物件__esModule屬性為true的話,表示這是一個es6的模組
__webpack_require__.r = function(exports) {
if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
}
Object.defineProperty(exports, '__esModule', { value: true });
}
/**
* 建立一個偽名稱空間物件
* mode & 1 value 是一個模組id,require(value)載入模組
* mode & 8 將value的所有屬性合併到ns物件當中
* mode & 4 返回已經是nsobject到value
* mode & 8 | 1 繫結getter方法
*/
__webpack_require__.t = function(value, mode) {
if(mode & 1) value = __webpack_require__(value);
if(mode & 8) return value;
if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
var ns = Object.create(null);
__webpack_require__.r(ns);
Object.defineProperty(ns, 'default', { enumerable: true, value: value });
if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
return ns;
}
//相容模組物件,給模組物件繫結getter方法
__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;
}
//Object.prototype.hasOwnProperty.call判斷物件有沒有某個屬性
__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
// __webpack_public_path__
__webpack_require__.p = "";
//__webpack_require__.s 模組id
return __webpack_require__(__webpack_require__.s = "./src/test.js");
})
({
"./src/b.js":(function(module, __webpack_exports__, __webpack_require__){
"use strict";
//判斷下exports是否是es模組內部方法掛載到exports物件上
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"log\", function() { return log; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"error\", function() { return error; });\nconst log = function (m) {\n console.log(m)\n }\n \n const error = function (m) {\n console.error(m)\n }\n\n//# sourceURL=webpack:///./src/b.js?");
}),
"./src/test.js":(function(module, __webpack_exports__, __webpack_require__){
"use strict";
//主模組,載入bmodule,並執行引入的module
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _b_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./b.js */ \"./src/b.js\");\n\nObject(_b_js__WEBPACK_IMPORTED_MODULE_0__[\"log\"])('hello')\n\n//# sourceURL=webpack:///./src/test.js?");
})
})