1. 程式人生 > >wepack的模塊化原理及配置方法

wepack的模塊化原理及配置方法

否則 mem 文件 完成後 加載 服務器 cal 其中 內部函數

我們都知道,webpack的特點之一就在於其的模塊化,將各個文件都使用loader功能轉換為js文件,並將其模塊化,那麽其模塊化的原理是什麽呢?

首先我們需要了解CommonJS規範,以及AMD、CMD、UMD規範都是什麽及其原理。

首先,CommonJS是在服務器端用於模塊化的規範,因為是同步的,所以只能在服務器端實現,而瀏覽器端因為缺少node的四個字段:

  • module
  • exports
  • require
  • global
// foobar.js 

//私有變量 
var test = 123; 

//公有方法 
function foobar () { 

    this.foo = function
() { // do someing ... } this.bar = function () { //do someing ... } } //exports對象上的方法和變量是公有的 var foobar = new foobar(); exports.foobar = foobar; //require方法默認讀取js文件,所以可以省略js後綴 var test = require(‘./boobar‘).foobar; test.bar();

因為沒辦法在瀏覽器使用這個規範,所有就用了AMD規範和CMD規範。

AMD規範是RequireJS 在推廣過程中對模塊定義的規範化產出的,異步使用回調來實現模塊化:

通過數組引入依賴 ,回調函數通過形參傳入依賴 
define([‘someModule1‘, ‘someModule2’], function (someModule1, someModule2) { 

    function foo () { 
        /// someing 
        someModule1.test(); 
    } 

    return {foo: foo} 
}); 
AMD規範允許輸出模塊兼容CommonJS規範,這時define方法如下: 

define(
function (require, exports, module) { var reqModule = require("./someModule"); requModule.test(); exports.asplode = function () { //someing } });

而CMD是SeaJS 在推廣過程中對模塊定義的規範化產出的

CMD和AMD的區別有以下幾點:

1.對於依賴的模塊AMD是提前執行,CMD是延遲執行。不過RequireJS從2.0開始,也改成可以延遲執行。

2.CMD推崇依賴就近,AMD推崇依賴前置。

//AMD 
define([‘./a‘,‘./b‘], function (a, b) { 

    //依賴一開始就寫好 
    a.test(); 
    b.test(); 
}); 

//CMD 
define(function (requie, exports, module) { 
     
    //依賴可以就近書寫 
    var a = require(‘./a‘); 
    a.test(); 
     
    ... 
    //軟依賴 
    if (status) { 
     
        var b = requie(‘./b‘); 
        b.test(); 
    } 
}); 

那麽我們接下來再看下webpack的模塊化是如何去實現的:

當我將一個依賴於main.js的entry.js打包的時候,整理其打包後的文件可以看到其結構如下:

(function (modules) {/* 省略函數內容 */})
([
function (module, exports, __webpack_require__) {
    /* 模塊index.js的代碼 */
},
function (module, exports, __webpack_require__) {
    /* 模塊bar.js的代碼 */
}
]);

其中函數內容:

// 1、模塊緩存對象
var installedModules = {};
// 2、webpack實現的require
function __webpack_require__(moduleId) {
    // 3、判斷是否已緩存模塊
    if(installedModules[moduleId]) {
        return installedModules[moduleId].exports;
    }
    // 4、緩存模塊
    var module = installedModules[moduleId] = {
        i: moduleId,
        l: false,
        exports: {}
    };
    // 5、調用模塊函數
    modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
    // 6、標記模塊為已加載
    module.l = true;
    // 7、返回module.exports
    return module.exports;
}
// 8、require第一個模塊
return __webpack_require__(__webpack_require__.s = 0);

我們可以看出:

1.首先webpack聲明了一個installedModules對象,用於緩存模塊

2.聲明了__webpack_require__內部函數,用於實現require功能,首先檢查緩存中是否存在要引用的模塊,如有的話return緩存中的該模塊,否則初始化該模塊,再返回該模塊

3.用完成後,模塊標記為已加載。

require入口模塊時,入口模塊會收到收到三個參數,下面是入口模塊代碼:

function(module, exports, __webpack_require__) {
    "use strict";
    var bar = __webpack_require__(1);
    bar();
}

webpack傳入的第一個參數module是當前緩存的模塊,包含當前模塊的信息和exports;第二個參數exportsmodule.exports的引用,這也符合commonjs的規範;第三個__webpack_require__ 則是require的實現。

在我們的模塊中,就可以對外使用module.exportsexports進行導出,使用__webpack_require__導入需要的模塊,代碼跟commonjs完全一樣。

這樣,就完成了對第一個模塊的require,然後第一個模塊會根據自己對其他模塊的require,依次加載其他模塊,最終形成一個依賴網狀結構。webpack管理著這些模塊的緩存,如果一個模塊被require多次,那麽只會有一次加載過程,而返回的是緩存的內容,這也是commonjs的規範。

這樣就完成了webpack hack commonjs的過程。

wepack的模塊化原理及配置方法