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

 

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