最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 基于webpack4.x模块依赖加载流程

    正文概述 掘金(isisxu)   2021-01-07   405

    模块依赖加载解析

    // webpack.config.js配置
    const path = require('path')
    module.exports = {
      devtool: 'none',		// 不生成映射url,也就是不生成source-map文件
      mode: 'development',	// development | production
      entry: './src/index.js',
      output: {
        path: path.resolve(__dirname, 'dist'),  // 在当前目录下添加dist目录,并且将输出的内容放在filename指定的文件中
        filename: 'bundle.[hash:8].js'          // bundle.[hash:8].js防止有缓存,所以每次生成不一样的bundle.js就是加hash,后面的 ':8'表示hash的位数
      },
      // 这里还配置了一些解析css的loader,省略了
     }
    
    // index.js
    require('./index.css')
    let aa = require('./a.js')
    console.log(aa);
    console.log('hello webpack');
    let fn = () => {
      console.log('我是fn');
    }
    fn()
    
    
    // a.js
    function testshow () {
      console.log('哈哈哈哈哈哈');
    }
    module.exports = testshow
    
    /* index.css */
    @import './a.css';
    body {
      background-color: pink;
      transform: rotate(45deg);
      background: url('./w3.png');
    }
    
    /* a.css */
    body{
      background-color: red;
    }
    
    // bundle.js
    (function (modules) {
      // 缓存模块对象,如果已经被缓存过了,就不需要再重新加载,直接从这个对象中获取模块文件moduleId对应的exports导出对象
      var installedModules = {};
      // webpack实现的require导入函数,这个函数用于递归导入依赖模块
      function __webpack_require__ (moduleId) {
        if (installedModules[moduleId]) {
          return installedModules[moduleId].exports;
        }
        var module = installedModules[moduleId] = {
          i: moduleId,	// moduleId是模块文件名,第一次传入模块文件就是./src/index.js
          l: false,		// 标记这个模块文件是否被加载过
          exports: {}	// moduleId对应的模块文件的导出的对象保存在这里
        };
        //  第一次的modules[moduleId]相当于modules[./src/index.js],获取到的是传入./src/index.js模块对应的函数
        // modules[moduleId].call() ,直接加载了moduleId模块文件对应的函数代码,并把函数内部的this指向改为module.exports,还把递归函数__webpack_require__传入。这样相当于执行了./src/index.js模块对象的函数,在函数中又有其他模块的导入,则可以使用__webpack_require__再进行递归加载
        modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
        
        // 标记moduleId这个模块已经被加载过了
        module.l = true;
        
        // 最终把导出返回,每个模块最终在这里把自己的模块导出对象exports返回到上一层调用处
        return module.exports;
      }
    
      // m属性向外暴露传入的模块参数对象
      __webpack_require__.m = modules;
    
      // c属性向外暴露缓存对象
      __webpack_require__.c = installedModules;
    
      // d方法兼容各种导出模式,重写getter方法
      __webpack_require__.d = function (exports, name, getter) {
        if (!__webpack_require__.o(exports, name)) {
          Object.defineProperty(exports, name, { enumerable: true, get: getter });
        }
      };
    
      // r方法用于是import导入方式时,则会给模块导出对象exports增加`__esModule`属性标记
      __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方法 todo暂时没看明白
      __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;
      };
    
      // 获取模块默认导出对象,是ES的导出方式,则使用default为默认导出对象,否则按照commonJS的默认导出module
      // 主要用于这种场景,导入导出不一致。如果在一个模块文件中,使用import导入了某模块,但是导入的这个模块又是以commonJS的方式导出的
      // 导入判断是否ES Module,采用r方法判断;导出是否使用ES Module采用n函数判断
      __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;
      };
    
      // o方法用于判断property属性是否是object对象自己的属性
      __webpack_require__.o = function (object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
    
      // p属性存放公共访问路径
      __webpack_require__.p = "";
    
      //__webpack_require__方法在这里调用,并且传入了配置的入口模块"./src/index.js"
      return __webpack_require__(__webpack_require__.s = "./src/index.js");		
    })
      ({
        "./src/a.js":
          (function (module, exports) {
            function testshow () {
              console.log('哈哈哈哈哈哈');
            }
            module.exports = testshow;
          }),
    
        "./src/index.css":
          (function (module, __webpack_exports__, __webpack_require__) {
            "use strict";
            // 由于index.css的源代码中使用ES Module导入的a.css,所以这里调r方法
            __webpack_require__.r(__webpack_exports__);
          }),
    
        "./src/index.js":
          (function (module, exports, __webpack_require__) {
            // __webpack_require__递归导入index.css,和a.js,就跟导入index.js一样
            __webpack_require__("./src/index.css");
            //  __webpack_require__("./src/a.js")返回的是a.js的导出export,然后赋值给aa
            var aa = __webpack_require__("./src/a.js");
            console.log(aa);
            console.log('hello webpack');
            var fn = function fn () {
              console.log('我是fn');
            };
            fn();
          })
      });
    

    基于webpack4.x模块依赖加载流程



    commonJS和ES Module的导入导出有区别

    // index.js
    // require('./index.css')
    // let aa = require('./a.js')
    import a from './a.js';
    import './index.css'
    let aa = a
    console.log(aa);
    console.log('hello webpack');
    let fn = () => {
      console.log('我是fn');
    }
    fn()
    
    
    
    // a.js
    function testshow () {
      console.log('哈哈哈哈哈哈');
    }
    module.exports = testshow
    
    // bundle.js 只截取了参数对象这部分
      ({
        "./src/a.js":
          (function (module, exports) {
            function testshow () {
              console.log('哈哈哈哈哈哈');
            }
            module.exports = testshow;
          }),
    
        "./src/index.css":
          (function (module, __webpack_exports__, __webpack_require__) {
            "use strict";
            __webpack_require__.r(__webpack_exports__);
          }),
    
        "./src/index.js":
          (function (module, __webpack_exports__, __webpack_require__) {
            "use strict";
            // r方法标识了index.js是个ESModule
            __webpack_require__.r(__webpack_exports__);
            var _a_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/a.js");
            // 因为a模块是import导入的,这里使用n方法判断出a.js的默认导出是commonJS的导出
            var _a_js__WEBPACK_IMPORTED_MODULE_0___default = __webpack_require__.n(_a_js__WEBPACK_IMPORTED_MODULE_0__);
            var _index_css__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__("./src/index.css");
            var aa = _a_js__WEBPACK_IMPORTED_MODULE_0___default.a;
            console.log(aa);
            console.log('hello webpack');
            var fn = function fn () {
              console.log('我是fn');
            };
            fn();
          })
      });
    


    模块依赖加载流程总结

    0. 自调用函数接收到modules模块集合对象开始执行
    1. 执行到 return __webpack_require__(__webpack_require__.s = "./src/index.js");时,调用webpack_require函数传入第一个模块文件index.js
    2. webpack_require函数内部开始执行,判断传入的模块index.js是否存在缓存中,有的话直接从缓存中返回导出index.js的export
    导出,没有则将其存入缓存,并创建新对象module。
    3. 直接获取index.js模块对应的函数,直接执行,并传入响应的参数
    4. 执行index.js对象的函数时发现导入了a.js和index.css————>注意这里采用webpack_require函数递归导入a.js等,就跟导入index.js一样,最终将返回的结果在webpack_require的return module.exports处返回对应模块的导出,接着回到index.js对应的方法webpack_require('a.js')获取到a.js模块的exports,然后在index.js中进行使用export导出的值。
    

    起源地下载网 » 基于webpack4.x模块依赖加载流程

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元