前言
又是偷懶了快一年。重新回歸簡(jiǎn)書的原因是一位同事百度async原理時(shí),第一篇竟然是我的文章簇捍。瞬間腰桿挺直,又堅(jiān)定了更博的信念够滑。
webpack模塊化的原理在網(wǎng)上已經(jīng)一搜一片垦写。但是對(duì)著文章讀吕世,始終不是你自己的彰触,切記不能背原理,面試官一深入問命辖,只能嗝屁况毅。
動(dòng)手
準(zhǔn)備2個(gè)JS分蓖。a.js,b.js。
a.js
let a = require('./b');
a()
b.js
module.exports = function(){
console.log('hello world')
}
進(jìn)行webpack編譯尔许,生成main.js么鹤。
先看看原來(lái)的JS都變成什么樣了
/* 0 */
(function(module, exports, __webpack_require__) {
let a = __webpack_require__(1); //b.js變成了1
a()
}),
/* 1 */
(function(module, exports) {
module.exports = function(){
console.log('hello world')
}
})
1、JS被包在一個(gè)函數(shù)里味廊,函數(shù)提供了module, exports,_webpack_require_參數(shù)蒸甜。
2、原來(lái)的require函數(shù)變成了_webpack_require_
3余佛、'b.js'文件名變成了模塊ID
回過來(lái)想也是應(yīng)該的柠新,瀏覽器沒有module和require,為了不報(bào)錯(cuò)辉巡,所以需要函數(shù)來(lái)提供module和require恨憎。
再來(lái)看下main.js的整體架構(gòu)
(function(modules) { //自執(zhí)行函數(shù)。module為包裹了函數(shù)的a.js,b.js
})([
(function(module, exports, __webpack_require__) {
console.log(module)
let a = __webpack_require__(1);
a()
}),
(function(module, exports) {
module.exports = function(){
console.log('hello world')
}
})
])
整體來(lái)說就是個(gè)自執(zhí)行函數(shù)郊楣。經(jīng)過處理的a.js,b.js作為參數(shù)傳入到自執(zhí)行函數(shù)憔恳。
function __webpack_require__(moduleId) {
// 判斷模塊是否已經(jīng)緩存過
if(installedModules[moduleId]) {
return installedModules[moduleId].exports;
}
// 沒有就初始化一個(gè)模塊
var module = installedModules[moduleId] = {
i: moduleId,
l: false,
exports: {}
};
//執(zhí)行被函數(shù)包裹后的js
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
// 記錄該模塊已經(jīng)被加載
module.l = true;
// 返回 module.exports,比如在b.js中module.exports被函數(shù)賦值了
return module.exports;
}
到此净蚤,捋一下main.js的執(zhí)行過程
1钥组、_webpack_require_(0)。
2塞栅、模塊0沒有被緩存過者铜,初始化module。
3放椰、從modules數(shù)組中取出0模塊作烟,即a.js。執(zhí)行
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
執(zhí)行_webpack_require_(1)砾医,加載b.js拿撩。
4、_webpack_require_函數(shù)return module.exports如蚜。在b.js中
module.exports = function(){
console.log('hello world')
}
module.exports已經(jīng)被賦值压恒,所以得到函數(shù)
5、至此错邦,依賴加載完畢,代碼也執(zhí)行完成探赫。
同理再看下ES6的Module
a.js
import a from './b'
function c(){
a()
}
export default c
b.js
export default function(){
console.log('hello world')
}
進(jìn)行webpack編譯,生成main.js撬呢。
看下原來(lái)的JS編譯后的樣子
[
/* 0 */
(function(module, __webpack_exports__, __webpack_require__) {
"use strict";
// ESM COMPAT FLAG
__webpack_require__.r(__webpack_exports__);
// CONCATENATED MODULE: ./b.js
var b = (function(){
console.log('hello world')
});
// CONCATENATED MODULE: ./a.js
function c(){
b()
}
var a = __webpack_exports__["default"] = (c);
})
]
在commonjs下伦吠,數(shù)組長(zhǎng)度為2。但在ES6規(guī)范下,數(shù)組長(zhǎng)度是1毛仪。exports被剝掉搁嗓,直接將2個(gè)JS粘合在了一起
_webpack_require_.r
// define __esModule on exports
__webpack_require__.r = function(exports) {
if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
}
Object.defineProperty(exports, '__esModule', { value: true });
};
標(biāo)記了這個(gè)模塊屬于ES6 Module。
其他都和commonjs一致箱靴,從_webpack_require_(0)開始
最后腺逛,給自己留個(gè)問題
為什么commonjs數(shù)組分開,而ES module卻直接粘合在一起衡怀。