webpack支持的模塊規(guī)范有?AMD?、CommonJS、ES2015 import?等規(guī)范。不管何種規(guī)范大致可以分為同步加載和異步加載兩種情況。本文將介紹webpack是如何實(shí)現(xiàn)模塊管理和加載。

創(chuàng)新互聯(lián)公司是一家專業(yè)的成都網(wǎng)站建設(shè)公司,我們專注網(wǎng)站建設(shè)、成都網(wǎng)站制作、網(wǎng)絡(luò)營銷、企業(yè)網(wǎng)站建設(shè),賣鏈接,廣告投放為企業(yè)客戶提供一站式建站解決方案,能帶給客戶新的互聯(lián)網(wǎng)理念。從網(wǎng)站結(jié)構(gòu)的規(guī)劃UI設(shè)計到用戶體驗提高,創(chuàng)新互聯(lián)力求做到盡善盡美。
同步加載如下:
import?a?from?'./a'; console.log(a);
異步加載如下:
import('./a').then(a?=>?console.log(a));webpacks實(shí)現(xiàn)的啟動函數(shù),直接將入口程序module傳入啟動函數(shù)內(nèi),并緩存在閉包內(nèi),如下:
(function(modules){
......
//?加載入口模塊并導(dǎo)出(實(shí)現(xiàn)啟動程序)
return?__webpack_require__(__webpack_require__.s?=?0);
})({
0:?(function(module,?__webpack_exports__,?__webpack_require__)?{
module.exports?=?__webpack_require__(/*!?./src/app.js?*/"./src/app.js");
})
})webpack在實(shí)現(xiàn)模塊管理上不管服務(wù)端還是客戶端大致是一樣,主要由installedChunks記錄已經(jīng)加載的chunk,installedModules記錄已經(jīng)執(zhí)行過的模塊,具體如下:
/**
*?module?緩存器
*?key?為?moduleId?(一般為文件路徑)
*?value?為?module?對象?{i:?moduleId,?l:?false,?exports:?{}}
*/
var?installedModules?=?{};
/**
*?chunks加載狀態(tài)記錄器
*?key?一般為?chunk?索引
*?value?undefined:未加載?0:已經(jīng)加載?(客戶端特有?null:?準(zhǔn)備加載?[resolve,?reject]:?加載中)
*/
var?installedChunks?=?{
"app":?0
}不管是服務(wù)端還是客戶端同步加載的方法都一樣,主要是檢測installedModules中是否已經(jīng)緩存有要加載的module,有則直接返回,否則就創(chuàng)建一個新的module,并執(zhí)行返回module.exports,具體實(shí)現(xiàn)如下:
//?編譯后的同步加載
__webpack_require__(/*!?./src/app.js?*/"./src/app.js");
//?加載模塊的方法,即require方法
function?__webpack_require__(moduleId)?{
//?檢查當(dāng)前的module是否已經(jīng)存在緩存中
if(installedModules[moduleId])?{
return?installedModules[moduleId].exports;?//?直接返回已緩存的?module.exports
}
//?創(chuàng)建一個新的?module,?并添加到緩存中
var?module?=?installedModules[moduleId]?=?{
i:?moduleId,
l:?false,?//?是否已經(jīng)加載
exports:?{}?//?暴露的對象
};
//?執(zhí)行當(dāng)前?module?的方法
modules[moduleId].call(module.exports,?module,?module.exports,?__webpack_require__);
//?標(biāo)記?module?加載完成狀態(tài)
module.l?=?true;
//?返回?module?暴露的?exports?對象
return?module.exports;
}服務(wù)端的異步加載是通過node的require方法加載chunk并返回一個promises對象。所有chunk都是暴露出ids和modules對象,具體實(shí)現(xiàn)如下:
//?編譯后的異步加載方法
__webpack_require__.e(/*!?import()?*/?0).then(__webpack_require__.bind(null,?/*!?./c.js?*/?"./src/c.js"))
//?chunk?0?代碼如下(即0.js的代碼)
exports.ids?=?[0];
exports.modules?=?{
"./src/c.js":?(function(module,?__webpack_exports__,?__webpack_require__)?{
"use?strict";
__webpack_require__.r(__webpack_exports__);
__webpack_exports__["default"]?=?(function?()?{
console.log('c');
})
})
}
//?異步加載模塊方法
__webpack_require__.e?=?function?requireEnsure(chunkId)?{
var?promises?=?[];
if(installedChunks[chunkId]?!==?0)?{
var?chunk?=?require("./"?+?({}[chunkId]||chunkId)?+?".js");
var?moreModules?=?chunk.modules,?chunkIds?=?chunk.ids;
for(var?moduleId?in?moreModules)?{
modules[moduleId]?=?moreModules[moduleId];
}
for(var?i?=?0;?i?<?chunkIds.length;?i++)
installedChunks[chunkIds[i]]?=?0;
}
return?Promise.all(promises);
}客戶端的異步加載是通過JSONP原理進(jìn)行加載資源,將chunk內(nèi)容([chunkIds, modules])存到全局的webpackJsonp數(shù)組中,并改造webpackJsonp的push方法實(shí)現(xiàn)監(jiān)聽chunk加載完成事件。具體實(shí)現(xiàn)如下:
//?編譯后的異步加載方法
__webpack_require__.e(/*!?import()?*/?0).then(__webpack_require__.bind(null,?/*!?./c.js?*/?"./src/c.js"))
//?chunk?0?代碼如下(即0.js的代碼)
(window["webpackJsonp"]?=?window["webpackJsonp"]?||?[]).push([[0],{
"./src/c.js":?(function(module,?__webpack_exports__,?__webpack_require__)?{
"use?strict";
__webpack_require__.r(__webpack_exports__);
__webpack_exports__["default"]?=?(function?()?{
console.log('c');
});
})
}]);
//?加載成功的回調(diào)函數(shù)
function?webpackJsonpCallback(data)?{
var?chunkIds?=?data[0];
var?moreModules?=?data[1];
//?將本次加載回來的?chunk?標(biāo)記為加載完成狀態(tài),并執(zhí)行回調(diào)
var?moduleId,?chunkId,?i?=?0,?resolves?=?[];
for(;i?<?chunkIds.length;?i++)?{
chunkId?=?chunkIds[i];
if(Object.prototype.hasOwnProperty.call(installedChunks,?chunkId)?&&?installedChunks[chunkId])?{
resolves.push(installedChunks[chunkId][0]);?//?將chunk成功回調(diào)添加到要執(zhí)行的隊列中
}
installedChunks[chunkId]?=?0;?//?將chunk標(biāo)記為加載完成
}
//?將本次加載回來的?module?添加到全局的?modules?對象
for(moduleId?in?moreModules)?{
if(Object.prototype.hasOwnProperty.call(moreModules,?moduleId))?{
modules[moduleId]?=?moreModules[moduleId];
}
}
//?判斷?webpackJsonp?數(shù)組原始的push方法是否存在,存在則將數(shù)據(jù)追加到webpackJsonp中
if(parentJsonpFunction)?parentJsonpFunction(data);
//?執(zhí)行所有?chunk?回調(diào)
while(resolves.length)?{
resolves.shift()();
}
};
//?加載完成監(jiān)聽方法的實(shí)現(xiàn)
var?jsonpArray?=?window["webpackJsonp"]?=?window["webpackJsonp"]?||?[];
var?oldJsonpFunction?=?jsonpArray.push.bind(jsonpArray);
jsonpArray.push?=?webpackJsonpCallback;
jsonpArray?=?jsonpArray.slice();
for(var?i?=?0;?i?<?jsonpArray.length;?i++)?webpackJsonpCallback(jsonpArray[i]);
var?parentJsonpFunction?=?oldJsonpFunction;
//?異步加載模塊方法
__webpack_require__.e?=?function?requireEnsure(chunkId)?{
var?promises?=?[];
var?installedChunkData?=?installedChunks[chunkId];
if(installedChunkData?!==?0)?{?//?0?時表示已經(jīng)安裝完成
if(installedChunkData)?{?//?加載中
promises.push(installedChunkData[2]);
}?else?{
//?創(chuàng)建一個回調(diào)的Promise,并將Promise緩存到installedChunks中
var?promise?=?new?Promise(function(resolve,?reject)?{
installedChunkData?=?installedChunks[chunkId]?=?[resolve,?reject];
});
promises.push(installedChunkData[2]?=?promise);
var?script?=?document.createElement('script');
var?onScriptComplete;
script.charset?=?'utf-8';
script.timeout?=?120;
if?(__webpack_require__.nc)?{
script.setAttribute("nonce",?__webpack_require__.nc);
}
script.src?=?jsonpScriptSrc(chunkId);
var?error?=?new?Error();
onScriptComplete?=?function?(event)?{?//?加載完成回調(diào)
//?避免IE內(nèi)存泄漏。
script.onerror?=?script.onload?=?null;
clearTimeout(timeout);?//?關(guān)閉超時定時器
var?chunk?=?installedChunks[chunkId];
if(chunk?!==?0)?{?//?未加載完成
if(chunk)?{?//?加載中
var?errorType?=?event?&&?(event.type?===?'load'???'missing'?:?event.type);
var?realSrc?=?event?&&?event.target?&&?event.target.src;
error.message?=?'Loading?chunk?'?+?chunkId?+?'?failed.\n('?+?errorType?+?':?'?+?realSrc?+?')';
error.name?=?'ChunkLoadError';
error.type?=?errorType;
error.request?=?realSrc;
chunk[1](error);
}
installedChunks[chunkId]?=?undefined;
}
};
var?timeout?=?setTimeout(function(){?//?設(shè)置超時定時器
onScriptComplete({?type:?'timeout',?target:?script?});
},?120000);
script.onerror?=?script.onload?=?onScriptComplete;?//?設(shè)置加載完成回調(diào)
document.head.appendChild(script);
}
}
return?Promise.all(promises);
};文章同步發(fā)布:?https://www.geek-share.com/detail/2784034803.html
參考文章:
詳解webpack + react + react-router 如何實(shí)現(xiàn)懶加載
Webpack2 + Vue2 + Vue-Router2 如何實(shí)現(xiàn)懶加載?
?
網(wǎng)頁名稱:webpack是如何實(shí)現(xiàn)模塊化加載的
當(dāng)前地址:http://www.chinadenli.net/article42/pisjhc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供Google、網(wǎng)站設(shè)計公司、靜態(tài)網(wǎng)站、App開發(fā)、域名注冊、面包屑導(dǎo)航
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)