探究 webpack 如何實現模塊化加載

探究 webpack 如何實現模塊化加載

最近稍稍比較忙,但還是要騰出時間來寫寫博客,博客真的是個好東西,只要你堅持。這次主要講講 webpack 打包後的代碼,分析他是如何實現模塊化(同步)加載模塊的,然後下次再講講如何按需(異步)加載模塊。

一、webpack 模塊化

關於模塊化,可以看看我之前的總結博客 js模塊化進程

總結一下,就是按照功能將一個項目切分成許多部分單獨開發,然後再組裝起來,每一個部分即爲模塊。

但是不管使用 require 還是 ES6 的 import ,最終都是經過 webpack 編譯,模擬該行爲,最後得到可執行代碼。

二、webpack 同步加載源碼

(1)源碼

我們直接用一個例子展示,使用打包配置

module.exports = {
  	mode: "development",
  	devtool: "source-map",
	...
}

主文件:

import func from './func.js'
func.add(1,2)

引用文件:

class func{
    add(val1,val2){
        return val1 + val2
    }
}

export default new func()

打包後源碼爲:

(function (modules) { // 立刻執行函數 webpackBootstrap
	var installedModules = {};	//緩存模塊
	function __webpack_require__(moduleId) {	//模塊加載函數
		......
	}
	......
	return __webpack_require__(__webpack_require__.s = "./src/index.js");
})({
	({		//引用文件
	 "./src/func.js":
		(function (module, __webpack_exports__, __webpack_require__) {
            class func {
                add(val1, val2) {
                    return val1 + val2
                }
            }
		)}
		__webpack_exports__["default"] = (new func());
	}),
	({		//主文件
	 "./src/index.js":
		(function (module, __webpack_exports__, __webpack_require__) {
			var _func_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/func.js");
			_func_js__WEBPACK_IMPORTED_MODULE_0__["default"].add(1, 2)
	})
});

1.使用了立刻執行函數的形式(webpackBootstrap),密閉空間。傳入一個對象 modules ,以文件名爲 key,value 是各個模塊內的代碼。

2.立刻執行函數內:

  • installedModules 對象用於緩存模塊
  • _webpack_require_ 是一個模塊加載函數,模擬 require 和 import
  • 最後加載了主文件代碼,主文件執行了 webpack_require 又引入了引用文件

(2)_webpack_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;
    }
  • 首先使用緩存看能否對象輸出模塊,緩存的目的其實就是加載時加速。
  • 沒有緩存則在對象內創建該模塊,設置 i(模塊ID),l(是否加載完成),exports(一個引用,指向模塊的導出對象)
  • 然後就是執行該模塊,通過 call 把 this 綁定在輸出模塊內。

同時觀察一下引用文件,它是通過 export 輸出內容的,而 export 正就是傳入該模塊的第三個參數 module.export。並且上述函數綁定的執行環境也是這個輸出模塊。通過相互循環引用,達成了拆分文件模塊後,調用時執行環境不變的效果。

當然,webpack 遠不止做了這些操作,本次只講了一個簡化的主流程。方便大家理解這個過程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章