• webpack-bundle.js原理


    bundle.js

    源码

    //a.js
    import { log } from './b.js'
    log('hello')
    
    //b.js
    export const log = function (m) {
      console.log(m)
    }
    
    export const error = function (m) {
      console.error(m)
    }
    

    自执行函数

    //其中 module0 和 module1 是我们的 a 和 b两个模块,不过也被一个函数包起来了。这段代码会把我们的模块放入一个数组,传给自执行函数,他来负责调用模块。
    
    (function(modules) {
        var installedModules = {};
        function __webpack_require__(moduleId) {}
        // Load entry module and return exports
        return __webpack_require__(__webpack_require__.s = 0);
    })
    (function (modules) {})([module0, module1])
    

    require模块

    function __webpack_require__(moduleId){
            //检查模块是否在缓存中
            if(installedModules[moduleId]) {
                return installedModules[moduleId].exports;
            }
            //创建一个新的模块并将其放入缓存中
            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;
    }
    
    

    require静态方法

    __webpack_require__.m = modules;//获取模块列表
    __webpack_require__.c = installedModules; //获取缓存模块列表
    __webpack_require__.d = function(exports, name, getter) {//定义一个getter方法
            if(!__webpack_require__.o(exports, name)) {
                Object.defineProperty(exports, name, { enumerable: true, get: getter });
            }
    }
      //如果此exports对象__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 });
    }
    
     /** 
         * 创建一个伪命名空间对象
         * mode & 1 value 是一个模块id,require(value)加载模块
         * mode & 8 将value的所有属性合并到ns对象当中
         * mode & 4 返回已经是nsobject到value
         * mode & 8 | 1 绑定getter方法
        */
     __webpack_require__.t = function(value, mode) {
            if(mode & 1) value = __webpack_require__(value);
            if(mode & 8) return value;
            if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
            var ns = Object.create(null);
            __webpack_require__.r(ns);
            Object.defineProperty(ns, 'default', { enumerable: true, value: value });
            if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
            return ns;
     }
    //兼容模块对象,给模块对象绑定getter方法
    __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 = "";
    
    

    依赖关系

    
    因为webpack从entry开始,对每一个 module 都进行处理,碰到 require 之后就跳入到对应的 module 的处理,也就是递归的对这颗依赖树进行处理,这是典型的深度优先遍历的递归解法,而且是先序优先遍历。处理的过程是这样的
    
    处理 main.js,记录入口 [main]
    碰到 require(a),记录 [main, a]
    进入到 a 模块,碰到语句 require(c), 记录下来 [main, a, c]
    同理碰到 require(d),记录下来 [main, a, c, d]
    返回到 main.js,下一句是 require('b'),记录下来 [main, a, c, d, b]
    进入模块 b,碰到语句 require(e),记录下来[main, a, c, d, b, e]
    返回,结束
    
    

    打包后代码

    (function(modules){
         /** 
         * {
         *   "./src/b.js":fn(...),
         *   "./src/test.js":fn(...)
         * }
         */
        //缓存模块
        var installedModules = {};
    
        //引入模块的方法
        function __webpack_require__(moduleId){
            //检查模块是否在缓存中
            if(installedModules[moduleId]) {
                return installedModules[moduleId].exports;
            }
            //创建一个新的模块并将其放入缓存中
            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 = modules;//获取模块列表
        __webpack_require__.c = installedModules; //获取缓存模块列表
         /**
            let obj={};
            let age='age';
            function getter() {
                return 9;
            }
            Object.defineProperty(obj,age,{enumerable: true,get: getter});
            console.log(obj.age)
        */
        //检查exports对象上有没有挂载name属性,没有就挂载一个
        __webpack_require__.d = function(exports, name, getter) {//定义一个getter方法
            if(!__webpack_require__.o(exports, name)) {
                Object.defineProperty(exports, name, { enumerable: true, get: getter });
            }
        }
         /**
          * 对象的Symbol.toStringTag属性,指向一个方法
          * 在该对象上面调用Object.prototype.toString方法时,如果这个属性存在,它的返回值会出现在toString方法返回的字符串之中,表示对象的类型
          * 也就是说,这个属性可以用来定制[object Object]或[object Array]中object后面的那个字符串
          * ({[Symbol.toStringTag]: 'Foo'}.toString())  "[object Foo]"
          */
          // define __esModule on exports 在导出对象上定义__esModule属性
          //如果此exports对象__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 });
        }
    
        /** 
         * 创建一个伪命名空间对象
         * mode & 1 value 是一个模块id,require(value)加载模块
         * mode & 8 将value的所有属性合并到ns对象当中
         * mode & 4 返回已经是nsobject到value
         * mode & 8 | 1 绑定getter方法
        */
        __webpack_require__.t = function(value, mode) {
            if(mode & 1) value = __webpack_require__(value);
            if(mode & 8) return value;
            if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
            var ns = Object.create(null);
            __webpack_require__.r(ns);
            Object.defineProperty(ns, 'default', { enumerable: true, value: value });
            if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
            return ns;
        }
    
        //兼容模块对象,给模块对象绑定getter方法
        __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 = "";
    
        //__webpack_require__.s 模块id
        return __webpack_require__(__webpack_require__.s = "./src/test.js");
    })
    ({
        "./src/b.js":(function(module, __webpack_exports__, __webpack_require__){
            "use strict";
            //判断下exports是否是es模块内部方法挂载到exports对象上
            eval("__webpack_require__.r(__webpack_exports__);
    /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "log", function() { return log; });
    /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "error", function() { return error; });
    const log = function (m) {
        console.log(m)
      }
      
      const error = function (m) {
        console.error(m)
      }
    
    //# sourceURL=webpack:///./src/b.js?");
        }),
        "./src/test.js":(function(module, __webpack_exports__, __webpack_require__){
            "use strict";
            //主模块,加载bmodule,并执行引入的module
            eval("__webpack_require__.r(__webpack_exports__);
    /* harmony import */ var _b_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./b.js */ "./src/b.js");
    
    Object(_b_js__WEBPACK_IMPORTED_MODULE_0__["log"])('hello')
    
    //# sourceURL=webpack:///./src/test.js?");
        })
    })
    
  • 相关阅读:
    [Java多线程]-并发,并行,synchonrized同步的用法
    [大数据可视化]-saiku的源码打包运行/二次开发构建
    [大数据可视化]-saiku的源码包Bulid常见问题和jar包
    [Java多线程]-线程池的基本使用和部分源码解析(创建,执行原理)
    [机器学习]-PCA数据降维:从代码到原理的深入解析
    [Java多线程]-Thread和Runable源码解析之基本方法的运用实例
    [Java多线程]-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类)
    [Java多线程]-Thread和Runable源码解析
    [机器学习]-Adaboost提升算法从原理到实践
    月是故乡明
  • 原文地址:https://www.cnblogs.com/pluslius/p/10267788.html
Copyright © 2020-2023  润新知