zoukankan      html  css  js  c++  java
  • webpack4打包文件结果原理解析

    首先上结论,简单来说就是:

    • 把解析的所有模块变成一个对象
    • 通过一个微入口去按顺序进行加载
    • 依次实现一个递归依赖关系
    • 通过入口对应的value(方法)去执行文件

    一、准备工作

    1-首先准备需要打包的demo :

    a.js

    module.exports = "学习webpack"  

    Index.js

    let str = require('./a.js')  
    console.log(str);  

    可以看出,代码的结果是打印 ”学习webpack

    2- 在package.json中进行以下打包指令配置

    "scripts": {  
     "build": "webpack --config webpack.config.my.js"  
    },  

    准备工作做好后就可以执行 npm run build 进行打包了

    二、分析文件

     

    dist目录(打包生成目录)中可以看到生成的bundle.js文件,原文件比较大,精简后可得到以下结果:

    现在我们来分析这个文件的打包原理:

    (function (modules) {
        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;
        }
    
        return __webpack_require__((__webpack_require__.s = "./src/index.js"));
    })({
        "./src/a.js":
            function (module, exports) {
                eval(
                    'module.exports = "学习webpack"
    
    //# sourceURL=webpack:///./src/a.js?'
                );
            },
        "./src/index.js":
            function (module, exports, __webpack_require__) {
                eval(
                    'let str = __webpack_require__(/*! ./a.js */ "./src/a.js")
    
    console.log(str);
    
    
    //# sourceURL=webpack:///./src/index.js?'
                );
            }
    });

    1. 看整体首先是一个匿名自执行函数,这是webpack启动函数

     

    2.执行的时候会传一个对象,对象有几部分,第一部分是我们的key第二部分是我们的value ;

    key -> 当前模块的路径 : value->函数, 将此对象传入module中

    ({
        "./src/a.js":
            function (module, exports) {
                eval(
                    'module.exports = "学习webpack"
    
    //# sourceURL=webpack:///./src/a.js?'
                );
            },
        "./src/index.js":
            function (module, exports, __webpack_require__) {
                eval(
                    'let str = __webpack_require__(/*! ./a.js */ "./src/a.js")
    
    console.log(str);
    
    
    //# sourceURL=webpack:///./src/index.js?'
                );
            }
    }); 

     

    3.先定义一个缓存,模块加载完了从缓存中拿 :

      var installedModules = {};
      /* 一个对象关系,例如 
      key -> "./src/index.js" 
      value -> {
          i: moduleId,
          l: false,
          exports: {}
        }
      */

    4. 实现一个require方法(require是不能在浏览器中运行的) :

      function __webpack_require__(moduleId) {  // "./src/index.js"
        // 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, // this 指向
          module, // 模块
          module.exports, // 模块空对象
          __webpack_require__ // 前面的 require 方法
        );
    
        // Flag the module as loaded
        module.l = true;
    
        // Return the exports of the module - 返回的结果
        return module.exports;
      }

    5. 在启动函数的结尾去调用 require 方法,

    并传入 在webpack.config.js配置文件中设定的入口模块, 这里是 "./src/index.js"

     

     

    6. 调用参数中入口模块对应的函数方法

     

     

    7. 可以看到该方法中存在一次递归关系,将 "./src/a.js" 再次传入require方法中找到以下函数,重走逻辑,找到以下方法:

     

    最后附上全注释版本:

    //webpack打包出的文件解析
    
    /*
      把解析的所有模块变成一个对象
      通过一个微入口去按顺序进行加载
      依次实现一个递归依赖关系
      通过入口对应的value(方法)去执行文件
    */
    
    //自执行函数 
    //对象当作参数传入整个 modules 里
    (function(modules) {
      // webpackBootstrap - webpack启动函数
      // The module cache - 先定义一个缓存,模块加载完了从缓存中拿
      var installedModules = {};
      /* 一个对象关系,例如 
      key -> "./src/index.js" 
      value -> {
          i: moduleId,
          l: false,
          exports: {}
        }
      */
    
      // The require function - 实现一个require方法(require是不能在浏览器中运行的)
      function __webpack_require__(moduleId) {  // "./src/index.js"
        // 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, // this 指向
          module, // 模块
          module.exports, // 模块空对象
          __webpack_require__ // 前面的 require 方法
        );
    
        // Flag the module as loaded
        module.l = true;
    
        // Return the exports of the module - 返回的结果
        return module.exports;
      }
    
      // Load entry module and return exports
      return __webpack_require__((__webpack_require__.s = "./src/index.js")); //传入入口模块
    })({
      //key -> 当前模块的路径 : value->函数  
      "./src/a.js": function(module, exports) {
        eval(
          // 最终的返回结果就是 "学习webpack"
          'module.exports = "学习webpack"
    
    //# sourceURL=webpack:///./src/a.js?'
        );
      },
    
      "./src/index.js": function(module, exports, __webpack_require__) {
        eval(
          // 再次找到 "./src/a.js" 传入__webpack_require__方法 重新再走流程,
          // 最终的返回结果就是 "学习webpack",将它赋值给 str 通过console.log()打印
          'let str = __webpack_require__("./src/a.js")
    
    console.log(str);
    
    
    //# sourceURL=webpack:///./src/index.js?'
        );
      }
    });
  • 相关阅读:
    python基础总结二
    HTTP和HTTPS的区别
    通过HTTP请求响应过程了解HTTP协议
    稳定性测试+易用性测试
    容错测试点
    功能测试思考点
    功能测试-UI测试思考点
    字符编码-11
    字典+再识函数-8
    web API的概念
  • 原文地址:https://www.cnblogs.com/anqwjoe/p/12289880.html
Copyright © 2011-2022 走看看