webpack的打包原理

 一、webpack的基本能力:處理依賴、模塊化、打包

     1、依賴管理:方便引用第三方模塊,讓模塊更容易複用、避免全局注入導致的衝突、、避免重複加載或者加載不必要的模塊

     2、合併代碼:把各個分散的模塊集中打包成大文件,減少HTTP的鏈接的請求次數,配合uglify.js可以減少、優化代碼的體積

     3、各種插件:babel把ES6+轉化爲ES5-,eslint可以檢查編譯時的各種錯誤

二、webpack的工作原理

      簡單的說就是分析代碼,找到“require”、“exports”、“define”等關鍵詞,並替換成對應模塊的引用。

      在一個配置文件中,指明對某些文件進行編譯、壓縮、組合等任務。把你的項目當成一個整體,通過一個給定的主文件  (index.js),webpack將從這個文件開始找到你的項目的所有的依賴文件,使用loaders處理他們,最後打包爲一個瀏覽器可 以識別的js文件。

三、手寫原理如下

(function (modules) {
    var installedModules = {};   //模塊緩存
    function __webpack_require__(moduleId) {
        if (installedModules[moduleId]) {
            return installedModules[moduleId].exports;
        }
        //創建一個新的模塊並賦值給module,並且放置到模塊的緩存(installedModules)中
        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;
    }

    //把模塊的定義對象緩存在_webpack_require_.m屬性上
    __webpack_require__.m=modules;
    // 把已經回去過的模塊組緩存放在__webpack_require__.c屬性上, 方便以後獲取
    __webpack_require__.c=installedModules;

    // 給一個對象增加一個屬性 d=defineProperty
    __webpack_require__.d=function(exports,name,getter){
        // o=hasOwnProperty
        if(__webpack_require__.o(exports,name)){
            Object.defineProperty(exports,name,{enumerable:true,get:getter});

        }
    }

    __webpack_require__.o=function(object,property){
        return Object.prototype.hasOwnProperty.call(object,property);
    }
    //表示這是一個es6模塊 esports.__esModule=true; 表示這是一個es6模塊。
    __webpack_require__.r=function(exports){
        if(typeof Symbol!=='undefined' &&Symbol.toStringTag){
            Object.defineProperty(exports,Symbol.toStringTag,{value:'Module'});
        }
        Object.defineProperty(exports,'_esModule',{value:true});
    }

    // 創建一個模擬的命名對象。
    // t的核心作用是把一個任意的模塊common.js es module 都包裝成es module的形式
    __webpack_require__.t=function(value,mode){

        // 如果與1爲true ,說明第一位是1,那麼則表示value是模塊ID,需要直接通過require加載,獲取它的module.exports對象
        // 0001
        if(mode &  1){ // 加載這個模塊ID,把value重新賦值爲導出對象
            value=__webpack_require__(value); // 從模塊ID變成了模塊的導出對象了。
        }
        // 1000 可以直接返回, 如果&1,&8,行爲類似於__webpack_require__
        if(mode & 8){
            return value;
        }

        //0100  如果與4 爲true 並且value有值,並且value._esModule 說明已經是一個esModule一個包裝過的模塊。
        if(mode & 4 && typeof value==='object' && value._esModules){
            return value;
        }
        
        var ns=Object.create(null); //創建一個新對象給他添加一個default屬性,屬性的值就是value。
        Object.defineProperty(ns,'default',{enumerable:true,value})

        // &2 等於 表示要把value所有屬性拷貝到命名空間上。ns
        if(mode & 2 && typeof value !=='string'){
            for(let key in value){
                __webpack_require__.d(ns,key,function(key){ return value[key]}.bind(null,key));

            }
        }

        return ns;  // 此方法會在後面加載懶加載的時候用到。
    }

    // publicPath 公開訪問路徑
    __webpack_require__.p='';
     return __webpack_require__(__webpack_require__.s="./src/index.js");
})
    (
        {
            "./src/index.js":
            (function (module, exports, __webpack_require__) {
                let title = __webpack_require__("./src/title.js");
                console.log(title);
            }),
            "./src/title.js":
            (function (module, exports) {

                console.log('title');
            })
        }
    )

// modules key 是模塊的相對路徑 ./src/index.js
// 值是一個value  是一個函數,格式有點像node中的node.js

 

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