成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

webpack模塊化原理-commonjs

molyzzx / 1566人閱讀

摘要:函數(shù)首先會檢查是否緩存了已加載的模塊,如果有則直接返回緩存模塊的。調(diào)用完成后,模塊標記為已加載。返回模塊的內(nèi)容。細心的你一定會發(fā)現(xiàn),文章到這里只介紹了對的實現(xiàn),那么是如何實現(xiàn)的呢歡迎閱讀本系列第二篇模塊化原理。

我們都知道,webpack作為一個構建工具,解決了前端代碼缺少模塊化能力的問題。我們寫的代碼,經(jīng)過webpack構建和包裝之后,能夠在瀏覽器以模塊化的方式運行。這些能力,都是因為webpack對我們的代碼進行了一層包裝,本文就以webpack生成的代碼入手,分析webpack是如何實現(xiàn)模塊化的。

PS: webpack的模塊不僅指js,包括css、圖片等資源都可以以模塊看待,但本文只關注js。

準備

首先我們創(chuàng)建一個簡單入口模塊index.js和一個依賴模塊bar.js:

//index.js
"use strict";
var bar = require("./bar");
function foo() {
    return bar.bar();
}
//bar.js
"use strict";
exports.bar = function () {
    return 1;
}

webpack配置如下:

var path = require("path");
module.exports = {
    entry: path.join(__dirname, "index.js"),
    output: {
        path: path.join(__dirname, "outs"),
        filename: "index.js"
    },
};

這是一個最簡單的配置,只指定了模塊入口和輸出路徑,但已經(jīng)滿足了我們的要求。

在根目錄下執(zhí)行webpack,得到經(jīng)過webpack打包的代碼如下(去掉了不必要的注釋):

(function(modules) { // webpackBootstrap
    // The module cache
    var installedModules = {};
    // The require function
    function __webpack_require__(moduleId) {
        // Check if module is in cache
        if(installedModules[moduleId]) {
            return installedModules[moduleId].exports;
        }
        // Create a new module (and put it into the cache)
        var module = installedModules[moduleId] = {
            i: moduleId,
            l: false,
            exports: {}
        };
        // Execute the module function
        modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
        // Flag the module as loaded
        module.l = true;
        // Return the exports of the module
        return module.exports;
    }
    // expose the modules object (__webpack_modules__)
    __webpack_require__.m = modules;
    // expose the module cache
    __webpack_require__.c = installedModules;
    // define getter function for harmony exports
    __webpack_require__.d = function(exports, name, getter) {
        if(!__webpack_require__.o(exports, name)) {
            Object.defineProperty(exports, name, {
                configurable: false,
                enumerable: true,
                get: getter
            });
        }
    };
    // getDefaultExport function for compatibility with non-harmony modules
    __webpack_require__.n = function(module) {
        var getter = module && module.__esModule ?
            function getDefault() { return module["default"]; } :
            function getModuleExports() { return module; };
        __webpack_require__.d(getter, "a", getter);
        return getter;
    };
    // Object.prototype.hasOwnProperty.call
    __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
    // __webpack_public_path__
    __webpack_require__.p = "";
    // Load entry module and return exports
    return __webpack_require__(__webpack_require__.s = 0);
})
/************************************************************************/
([
/* 0 */
(function(module, exports, __webpack_require__) {

"use strict";

var bar = __webpack_require__(1);
bar.bar();

}),
/* 1 */
(function(module, exports, __webpack_require__) {

"use strict";

exports.bar = function () {
    return 1;
}

})
]);
分析

上面webpack打包的代碼,整體可以簡化成下面的結構:

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

可以看到,整個打包生成的代碼是一個IIFE(立即執(zhí)行函數(shù)),函數(shù)內(nèi)容我們待會看,我們先來分析函數(shù)的參數(shù)。

函數(shù)參數(shù)是我們寫的各個模塊組成的數(shù)組,只不過我們的代碼,被webpack包裝在了一個函數(shù)的內(nèi)部,也就是說我們的模塊,在這里就是一個函數(shù)。為什么要這樣做,是因為瀏覽器本身不支持模塊化,那么webpack就用函數(shù)作用域來hack模塊化的效果。

如果你debug過node代碼,你會發(fā)現(xiàn)一樣的hack方式,node中的模塊也是函數(shù),跟模塊相關的參數(shù)exportsrequire,或者其他參數(shù)__filename__dirname等都是通過函數(shù)傳值作為模塊中的變量,模塊與外部模塊的訪問就是通過這些參數(shù)進行的,當然這對開發(fā)者來說是透明的。

同樣的方式,webpack也控制了模塊的moduleexportsrequire,那么我們就看看webpack是如何實現(xiàn)這些功能的。

下面是摘取的函數(shù)內(nèi)容,并添加了一些注釋:

// 1、模塊緩存對象
var installedModules = {};
// 2、webpack實現(xiàn)的require
function __webpack_require__(moduleId) {
    // 3、判斷是否已緩存模塊
    if(installedModules[moduleId]) {
        return installedModules[moduleId].exports;
    }
    // 4、緩存模塊
    var module = installedModules[moduleId] = {
        i: moduleId,
        l: false,
        exports: {}
    };
    // 5、調(diào)用模塊函數(shù)
    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);

模塊數(shù)組作為參數(shù)傳入IIFE函數(shù)后,IIFE做了一些初始化工作:

IIFE首先定義了installedModules ,這個變量被用來緩存已加載的模塊。

定義了__webpack_require__ 這個函數(shù),函數(shù)參數(shù)為模塊的id。這個函數(shù)用來實現(xiàn)模塊的require。

__webpack_require__ 函數(shù)首先會檢查是否緩存了已加載的模塊,如果有則直接返回緩存模塊的exports。

如果沒有緩存,也就是第一次加載,則首先初始化模塊,并將模塊進行緩存。

然后調(diào)用模塊函數(shù),也就是前面webpack對我們的模塊的包裝函數(shù),將modulemodule.exports__webpack_require__作為參數(shù)傳入。注意這里做了一個動態(tài)綁定,將模塊函數(shù)的調(diào)用對象綁定為module.exports,這是為了保證在模塊中的this指向當前模塊。

調(diào)用完成后,模塊標記為已加載。

返回模塊exports的內(nèi)容。

利用前面定義的__webpack_require__ 函數(shù),require第0個模塊,也就是入口模塊。

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

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

webpack傳入的第一個參數(shù)module是當前緩存的模塊,包含當前模塊的信息和exports;第二個參數(shù)exportsmodule.exports的引用,這也符合commonjs的規(guī)范;第三個__webpack_require__ 則是require的實現(xiàn)。

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

這樣,就完成了對第一個模塊的require,然后第一個模塊會根據(jù)自己對其他模塊的require,依次加載其他模塊,最終形成一個依賴網(wǎng)狀結構。webpack管理著這些模塊的緩存,如果一個模塊被require多次,那么只會有一次加載過程,而返回的是緩存的內(nèi)容,這也是commonjs的規(guī)范。

結論

到這里,webpack就hack了commonjs代碼。

原理還是很簡單的,其實就是實現(xiàn)exportsrequire,然后自動加載入口模塊,控制緩存模塊,that"s all。

細心的你一定會發(fā)現(xiàn),文章到這里只介紹了webpack對commonjs的實現(xiàn),那么ES6 module是如何實現(xiàn)的呢?
歡迎閱讀本系列第二篇《webpack模塊化原理-ES6 module》。

文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉載請注明本文地址:http://systransis.cn/yun/84326.html

相關文章

  • webpack組織模塊原理 - 基礎篇

    摘要:每一個模塊的源代碼都會被組織在一個立即執(zhí)行的函數(shù)里。接下來看的生成代碼可以看到,的源代碼中關于引入的模塊的部分做了修改,因為無論是,或是風格的,都無法被解釋器直接執(zhí)行,它需要依賴模塊管理系統(tǒng),把這些抽象的關鍵詞具體化。 現(xiàn)在前端用Webpack打包JS和其它文件已經(jīng)是主流了,加上Node的流行,使得前端的工程方式和后端越來越像。所有的東西都模塊化,最后統(tǒng)一編譯。Webpack因為版本的...

    leiyi 評論0 收藏0
  • webpack組織模塊原理 - external模塊

    摘要:所以通常情況下當你的庫需要依賴到例如,這樣的通用模塊時,我們可以不將它打包進,而是在的配置中聲明這就是在告訴請不要將這個模塊注入編譯后的文件里,對于我源代碼里出現(xiàn)的任何這個模塊的語句,請將它保留。 這篇文章討論Webpack打包library時經(jīng)常需要用到的一個選項external,它用于避免將一些很通用的模塊打包進你發(fā)布的library里,而是選擇把它們聲明成external的模塊,...

    Lavender 評論0 收藏0
  • webpack組織模塊原理 - 打包Library

    摘要:所以你編譯后的文件實際上應當只輸出,這就需要在配置里用來控制這樣上面的模塊加載函數(shù)會在返回值后面加一個,這樣就只返回的部分。 之前一篇文章分析了Webpack打包JS模塊的基本原理,所介紹的案例是最常見的一種情況,即多個JS模塊和一個入口模塊,打包成一個bundle文件,可以直接被瀏覽器或者其它JavaScript引擎執(zhí)行,相當于直接編譯生成一個完整的可執(zhí)行的文件。不過還有一種很常見的...

    legendmohe 評論0 收藏0
  • Javascript 塊化指北

    摘要:打包出來的代碼快照如下,注意看注釋中的時序實際上,的處理同相差無幾,只是在定義模塊和引入模塊時會去處理標識,從而兼容其在語法上的差異。 前言 隨著 Web 技術的蓬勃發(fā)展和依賴的基礎設施日益完善,前端領域逐漸從瀏覽器擴展至服務端(Node.js),桌面端(PC、Android、iOS),乃至于物聯(lián)網(wǎng)設備(IoT),其中 JavaScript 承載著這些應用程序的核心部分,隨著其規(guī)?;?..

    enali 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<