likes
comments
collection
share

Webpack——编译结果简化分析本文将以两个基础模块为例,模拟一个简化的webpack编译结果,将编译结果中的每个部分

作者站长头像
站长
· 阅读数 19

📚Webpack作为现代前端开发中的核心构建工具,以其强大的模块打包能力而广受欢迎。然而,对于初学者而言,编译后的代码往往是复杂且难以理解的。为了更好地学习Webpack的工作原理,本文将从一个实际的角度出发,对编译结果进行简化分析。

本文将以两个基础模块为例,模拟一个简化的编译结果,将编译结果中的每个部分逐一拆解,用浅显的语言解释其作用和意义。

🌟通过本文,你将能够:

  • 识别编译后代码的关键组成部分。
  • 学会如何阅读和分析Webpack的输出结果。

下面,正文开始

一、示例的两个模块

src下有两个模块

// a.js
console.log("module a")
module.exports = "a";
// index.js
console.log("index module")
var a = require("./a")
a.abc();
console.log(a)

二、编译结果的结构

npm run dev后,得到dist/main.js

代码太长,收起来看一下结构

Webpack——编译结果简化分析本文将以两个基础模块为例,模拟一个简化的webpack编译结果,将编译结果中的每个部分 这是一个立即执行函数

后面的({...})是立即执行函数的参数,是一个对象字面量, 在模块化的场景中,这通常代表了一组模块的定义或者依赖关系。

  • 这种结构通常用于实现模块化加载器(如类似于Webpack、Rollup等打包工具生成的代码),它们会将模块打包成一个函数或对象,然后作为参数传递给这个立即执行的函数。
  • 在函数内部,可以通过处理 modules 对象来加载和管理模块,实现模块化加载和依赖管理的功能。

示例

(function(modules) {
    function __webpack_require__(moduleId) {
       
        return ...;
    }
    return __webpack_require__(module0);
})({
    module0: function(module, exports, __webpack_require__) {
        console.log('Hello World');
    },
    module1: function(module, exports, __webpack_require__) {
        console.log('Another Module');
    }
});


展开,

立即执行函数的参数({...})对应的是:

Webpack——编译结果简化分析本文将以两个基础模块为例,模拟一个简化的webpack编译结果,将编译结果中的每个部分

立即执行函数对应的是:

Webpack——编译结果简化分析本文将以两个基础模块为例,模拟一个简化的webpack编译结果,将编译结果中的每个部分

三、简化编译结果

1. 参数内容

(function(modules){

})({//该对象保存了所有的模块,以及模块对应的代码
    "./src/a.js": function (module, exports) {
       console.log("module a")
       module.exports = "a";
    },
    "./src/index.js": function (module, exports, require) {
        console.log("index module")
        var a = require("./src/a.js")
        console.log("a")
    }
})

把对象作为字面量传入立即执行函数,避免污染全局变量,同时把模块构建好。

立即执行函数的modules传入所有模块

2. 函数体

(function(modules){
     //require函数相当于是运行一个模块,得到模块导出结果
    function require(moduleId) { //moduleId就是模块的路径
       
        var func = modules[moduleId]; //得到该模块对应的函数
        var module = {
            exports: {}
        }
        func(module, module.exports, require); //运行模块
        var result = module.exports; //得到模块导出的结果
        
        return result;
    }

    //执行入口模块
    require("./src/index.js"); //require函数相当于是运行一个模块,得到模块导出结果
})
   

立即执行函数里要传入require函数,因为模块代码里引用其他模块,require函数相当于是运行一个模块,得到模块导出结果

3. 进一步完善:增加缓存

Webpack——编译结果简化分析本文将以两个基础模块为例,模拟一个简化的webpack编译结果,将编译结果中的每个部分

eval

简化后的模拟编译结果与真实的编译结果作对比,基本一致,但发现模块的内容放进了eval里

Webpack——编译结果简化分析本文将以两个基础模块为例,模拟一个简化的webpack编译结果,将编译结果中的每个部分

为什么把模块放入eval里? 与浏览器有关,为了方便调试

使用eval示例:

使用刚才简化的编译后的代码,不使用eval包裹模块

给index.js加入一句会报错的代码

Webpack——编译结果简化分析本文将以两个基础模块为例,模拟一个简化的webpack编译结果,将编译结果中的每个部分

Webpack——编译结果简化分析本文将以两个基础模块为例,模拟一个简化的webpack编译结果,将编译结果中的每个部分 点击进入,可以看到:

Webpack——编译结果简化分析本文将以两个基础模块为例,模拟一个简化的webpack编译结果,将编译结果中的每个部分

如果不写在eval里,只能在main文件里调试。

改为eval包裹

Webpack——编译结果简化分析本文将以两个基础模块为例,模拟一个简化的webpack编译结果,将编译结果中的每个部分

此时查看报错,可以看到,右边显示了位置

Webpack——编译结果简化分析本文将以两个基础模块为例,模拟一个简化的webpack编译结果,将编译结果中的每个部分 点击进入源代码

Webpack——编译结果简化分析本文将以两个基础模块为例,模拟一个简化的webpack编译结果,将编译结果中的每个部分

浏览器支持eval里的代码在另一个环境执行。eval里的代码是放在另一个环境里去执行的,因此调试时看不到其他代码的干扰。

显示位置的文字是可以修改的,在eval后面的 //# sourceURL=webpack:///./src/index.js修改即可。 比如改为//# sourceURL=webpack:///./src/indexOOO.js

报错位置的显示为

Webpack——编译结果简化分析本文将以两个基础模块为例,模拟一个简化的webpack编译结果,将编译结果中的每个部分

注:生产环境相比于开发环境,会进一步压缩,变量名简化,换行取消等

扩展:

为什么要使用函数来包裹模块

  • 作用域隔离: 每个模块都有自己的私有作用域,防止变量名冲突。
  • 模块化管理: 模拟 Node.js 的模块系统,使得代码更符合 CommonJS 标准。
  • 优化和扩展: 便于实现各种优化技术和插件机制,如代码分割、缓存和热模块替换等。
转载自:https://juejin.cn/post/7380200984058707994
评论
请登录