標籤:cal 開始 改變 解鎖 引用 ddn cdata 綁定 運行機制
webpack模組機制淺析【一】
今天看了看webpack打包後的代碼,所以就去分析了下代碼的運行機制。
下面這段代碼是webpack打包後的最基本的形式,可以說是【骨架】
(function(root,fn){ if(typeof exports ===‘object‘&&typeof module === ‘object‘){ module.exports = fn();//exports和module同時存在,說明時在node的CommonJs規範下,這個時候使用module.exports來匯出模組,fn函數執行後是返回一個模組 }else if(typeof define === ‘function‘ && define.amd){ define([],fn);//當exports和module不同時存在時,先判斷define和define.amd是否存在;如果存在表明在AMD規範下,所以就使用define函數"包裹"一下fn函數,以此來聲明一個AMD規範下的模組 }else if(typeof exports === ‘object‘){ exports[‘packname‘] = fn();//packname表示的包名,exports據說是module.exports的引用,但是我不明白module不存在何來exports,求網友解答,不清楚什麼時候代碼能夠執行到這裡? }else { root[‘packname‘] = fn();//這個應該是如果上面的情況都不存在那就把它綁定在當前執行環境的"根節點",如在瀏覽器下就綁定在window上; }})(this,function(){//this丟進去變成了root,後面這個function丟進去就是fn return (function(modules){//modules是參數丟進來的函數數組 var installed = {};//用來裝載已聲明模組 function _webpack_require_(moduleId){//webpack的包擷取函數,使用這個函數去檢索前面傳進來的modules函數數組,從而解鎖出每一個函數數組中的元素(也可以說是模組),每一個數組元素一般都是會存在閉包以隔離範圍,每一個元素中會使用module.exports來作為輸出寄託對象。 if(installed[moduleId]){//moduleId其實就是modules數組的索引 return installed[moduleId].exports;//如果存在說明之前函數執行過 } var module = installed[moduleId] = {//可以說是緩衝模組 exports:{},//這個會使用下面的call函數來改變。 id:moduleId, loaded:false } modules[moduleId].call(module.exports,module,module.exports,_webpack_require_) //上面一句中,其實是執行modules[moduleId]()函數,只不過函數this指向了module.exports(也就是this) //還是上面一句解釋(因為重要啊):第二個參數module其實是一個【地址引用】,只要執行函數在函數中對這個module做了更改,那麼最開始的module就做了更改,這也是為什麼後面的函數數組中的函數都把方法和變數都綁定在module.exports上面的原因 module.loaded = true;//可以不管 return module.exports;//這個很重要,這個時候module.exports已經被上面的call函數裝飾過了。在經過無數個函數的洗禮之後,這個module.exports會逐漸成長為包含各種變數和方法的【大對象】,反正就是個對象,最後return丟給外層的module.exports或者this或者丟給AMD的define可以。 } _webpack_require_.m = modules;//這個先可以不管 _webpack_require_.c = installed;//緩衝,先不管 _webpack_require_.p = ‘‘;//先不管 return _webpack_require_(0);//這個是函數執行的入口,相當於執行modules[0]函數,可以在modules的第一個函數中再去調用其他函數 })([//注意這是一個函數數組,裡面都是函數,也可以理解為模組 function(module,exports,_webpack_require_){ // console.log(‘hi‘); console.log(this);//如果在下沒猜錯的話,下面幾個函數中的this輸出都是{},也就是_webpack_require_一開始定義modules下的exports(初始化為{}),對吧? module.exports = _webpack_require_(1); }, function(module,exports,_webpack_require_){ console.log(this);//{} let str = _webpack_require_(2);//調用其他模組 let isType = _webpack_require_(3); module.exports = {age:18,str:str,isType:isType}; }, function(module,exports,_webpack_require_){ console.log(this);//{} module.exports = ‘你好‘ }, function(module,exports,_webpack_require_){ console.log(this);//{} module.exports = function(type){ return function(obj){//返回一個函數 return Object.prototype.toString.call(obj) === "[object "+type+"]";//判斷變數類型的黑科技 } } } ]);})/*********/if(typeof module ==‘object‘ && typeof exports == ‘object‘){ console.log(module.exports);//{ age: 18, str: ‘你好‘, isType: [Function] } var isArray = module.exports.isType("Array");//返回的是一個函數 console.log(isArray([1]));//true console.log(isArray(‘1‘));//false console.log(isArray(1));//false}else if(typeof define == ‘function‘){ console.log(‘AMD‘);}else{ console.log(this); var isArray = this.isType("Array");//返回的是一個函數 console.log(isArray([1]));//true console.log(isArray(‘1‘));//false console.log(isArray(1));//false}
理解這個對於理解別人源碼會有協助,如果你不懶,我覺得你應該會把這段代碼執行一下(用node執行)
webpack模組機制淺析【一】