成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

webpack模塊化原理-commonjs

molyzzx / 1618人閱讀

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

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

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

準(zhǔn)備

首先我們創(chuàng)建一個(gè)簡單入口模塊index.js和一個(gè)依賴模塊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"
    },
};

這是一個(gè)最簡單的配置,只指定了模塊入口和輸出路徑,但已經(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打包的代碼,整體可以簡化成下面的結(jié)構(gòu):

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

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

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

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

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

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

// 1、模塊緩存對(duì)象
var installedModules = {};
// 2、webpack實(shí)現(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、標(biāo)記模塊為已加載
    module.l = true;
    // 7、返回module.exports
    return module.exports;
}
// 8、require第一個(gè)模塊
return __webpack_require__(__webpack_require__.s = 0);

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

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

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

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

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

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

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

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

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

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

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

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

在我們的模塊中,就可以對(duì)外使用module.exportsexports進(jìn)行導(dǎo)出,使用__webpack_require__導(dǎo)入需要的模塊,代碼跟commonjs完全一樣。

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

結(jié)論

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

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

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

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/84326.html

相關(guān)文章

  • webpack組織模塊原理 - 基礎(chǔ)篇

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

    leiyi 評(píng)論0 收藏0
  • webpack組織模塊原理 - external模塊

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

    Lavender 評(píng)論0 收藏0
  • webpack組織模塊原理 - 打包Library

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

    legendmohe 評(píng)論0 收藏0
  • Javascript 塊化指北

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

    enali 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<