打包后的源碼分析
// /src/index.js
import name from './login'
console.log('index.js=[' + name + ']')
// /src/login.js
module.exports = "zce"
// dist/built.js
(function (modules) {
// 01 定義對象用于將來緩存被加載過的模塊
let installedModules = {}
// 02 定義一個 __webpack_require__ 方法來替換 import require 加載操作
function __webpack_require__(moduleId) {
// 2-1 判斷當(dāng)前緩存中是否存在要被加載的模塊內(nèi)容执虹,如果存在則直接返回
if (installedModules[moduleId]) {
return installedModules[moduleId].exports
}
// 2-2 如果當(dāng)前緩存中不存在统刮,需要我們自己定義{} 執(zhí)行被導(dǎo)入的模塊內(nèi)容加載
let module = installedModules[moduleId] = {
i: moduleId,
l: false,
exports: {}
}
// 2-3 調(diào)用當(dāng)前 moduleId 對應(yīng)的函數(shù)福也,完成內(nèi)容的加載
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__)
// 2-4 當(dāng)上述的方法調(diào)用完成之后此洲,我們就可以修改 l 的值用于表示當(dāng)前模塊內(nèi)容已經(jīng)加載完成了
module.l = true;
// 2-5 加載工作完成之后,要將拿回來的內(nèi)容返回至調(diào)用的位置
return module.exports
}
// 03 定義 m 屬性用于保存 modules
__webpack_require__.m = modules
// 04 定義 c 用戶保存緩存 catch
__webpack_require__.c = installedModules
// 05 定義 o 方法判斷對象的身上是否存在指定的屬性
__webpack_require__.o = function (object, property) {
return Object.prototype.hasOwnProperty(object, property)
}
// 06 定義 d 方法用于在對象的身上添加指定的屬性,同時給該屬性提供一個 getter
__webpack_require__.d = function (exports, name, getter) {
if (!__webpack_require__.o(exports, name)) {
Object.defineProperty(exports, name, { enumerable: true, get: getter })
}
}
// 07 定義 r 方法 用于標(biāo)識當(dāng)前模塊是 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 })
}
// 08 定義 n 方法 用于設(shè)置具體的 getter
__webpack_require__.n = function(module) {
let getter = module && modules.__esModule ?
function getDefault() { return module['default'] } :
function getmoduleExports() { return module }
__webpack_require__.d(getter, 'a', getter)
}
// 09 定義 p 屬性胡控, 用于保存資源訪問路徑
__webpack_require__.p = ""
// 調(diào)用 __webpack_require__ 方法 執(zhí)行模塊 導(dǎo)入與加載操作
return __webpack_require__(__webpack_require__.s = './src/index.js')
})
({
"./src/index.js":
(function (module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
var _login_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./login.js */ "./src/login.js");
console.log('index.js 執(zhí)行了')
console.log(_login_js__WEBPACK_IMPORTED_MODULE_0__["default"], '<------')
console.log(_login_js__WEBPACK_IMPORTED_MODULE_0__["age"], '<------')
}),
"./src/login.js":
(function (module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
__webpack_require__.d(__webpack_exports__, "age", function () { return age; });
__webpack_exports__["default"] = ('小明是一個帥哥');
const age = 40
})
})
如何實(shí)現(xiàn)的懶加載
- import() 嗯可以實(shí)現(xiàn)指定模塊的懶加載操作
- 當(dāng)前懶加載的核心原理就是
jsonp
-
t
方法可以針對于內(nèi)容進(jìn)行不同的處理(處理方式取決于傳入的數(shù)值 8 6 7 3 2 1)
t方法分析及實(shí)現(xiàn)
// 11 定義 t 方法,用于加載指定 value 的模塊內(nèi)容旁趟,之后對內(nèi)容進(jìn)行處理再返回
__webpack_require__.t = function (value, mode) {
// 01 加載 value 對應(yīng)的模塊內(nèi)容( value 一般就是模塊 id )昼激,第二個值 mode 是一個二進(jìn)制的數(shù)值
// 02 t 方法內(nèi)部做的第一件事情就是調(diào)用自定義的 require 方法加載 value 對應(yīng)的模塊導(dǎo)出,
// 加載之后的內(nèi)容又重新賦值給 value 變量
// 03 當(dāng)獲取 到了這個 value 值之后余下的 8 4 ns 2 都是對當(dāng)前的內(nèi)容進(jìn)行加工處理锡搜,然后返回使用
// 04 當(dāng) mode & 8 成立時直接將 value 返回 ( commonJS)
// 05 當(dāng) mode & 4 成立時直接將 value 返回 ( esModule )
// 06 如果上述條件都不成立橙困,還是要繼續(xù)處理 value, 定義一個 ns {}
// 6-1 如果拿到的 value 是一個可以直接使用的內(nèi)容,例如是一個字符趾耕餐,將它掛載到 ns 的 default 屬性上
// 6-2 如果拿到的 value 是一個對象凡傅,則調(diào)用 d 方法添加屬性和 getter 方法
if (mode & 1) {
value = __webpack_require__(value)
}
if (mode & 8) { // 加載了可以直接返回使用的內(nèi)容 1 和 8 說明是一個commonjs內(nèi)容
return value
}
if ((mode & 4) && typeof value === 'object' && value && value.__esModule) {
return value
}
// 如果 8 和 4 都沒有成立則需要自定義 ns 來通過 default 屬性返回內(nèi)容
let 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
}
tapable工作流程
- 實(shí)例化
hook
注冊事件監(jiān)聽 - 通過
hook
觸發(fā)事件監(jiān)聽 - 執(zhí)行懶編譯生成的可執(zhí)行代碼
Hook
本質(zhì)是 tapbale
實(shí)例對象
-
Hook
執(zhí)行機(jī)制可分為同步和異步
Hook
執(zhí)行特點(diǎn)
-
Hook
: 普通鉤子,監(jiān)聽器之間互相獨(dú)立不干擾 -
BailHook
: 熔斷鉤子肠缔,某個監(jiān)聽返回非undefined
時后續(xù)不執(zhí)行 -
WaterfallHook
: 瀑布鉤子夏跷,上一個監(jiān)聽的返回值可傳遞至下一個 -
LoopHook
: 循環(huán)鉤子,如果當(dāng)前未返回false
則一直執(zhí)行
tapable
庫同步鉤子
SyncHook
SyncBailHook
SyncWaterfallHook
SyncLoopHook
tapable
庫異步串行鉤子
AsyncSeriesHook
AsyncSeriesBailHook
AsyncSeriesWaterfallHook
tapable
庫異步并行鉤子
AsyncParalleHook
AsyncParalleBailHook
Ast 在線調(diào)試
astexplorer.net