Webpack模块化原理图解

更新日期: 2021-02-02 阅读: 2.9k 标签: Webpack

为什么需要模块化

场景1

A同学开发了模块a,B同学开发了模块b,在页面下通过如下方式进行引用

<script src="a.js"></script>
<script src="b.js"></script>

这时模块a,模板b中的代码都暴露在全局环境中,如果模块a中定义了一个方法del。同学b并不知道,在模块b中也定义了一个方法del。这时便造成了命名冲突的的问题。如图


场景2

C同学开发了一个公共的工具库utils.js,D同学开发了一个公共的组件tab.js,tab.js依赖utils.js。同学E需要使用D同学开发的tab.js,就需要通过如下方式引用

<script src="util.js"></script>
<script src="tab.js"></script>

同学E自己也开发了一个dailog.js同时它也依赖util.js。现在页面同时引用了dialog.js和tab.js,代码如下

<script src="util.js"></script>
<script src="dialog.js"></script>
<scrpt src="tab.js"></script>

同学E不仅需要同时引用这三个js文件,还必须保证文件之间的引用顺序是正确的。同时,从上面的代码我们无法直接看出模块与模块之间的依赖关系,如果不深入tab.js,我们无法知道tab.js到底是只依赖util.js还是dialog.js或者两者都依赖。随着项目逐渐增大,不同模块之间的依赖关系则会变的越来越难以维护也会导致许多模块中大量的变量都暴露在全局环境中。


模块化的几种实现方案

模块化的规范有很多种, 如下
| 规范 | 实现方案 |
| --- | --- |
| CommonJS | node.js |
| AMD | Require.js |
| CMD | Sea.js
| UMD | |
| ES6 Module | |

webpack支持CommonJS,AMD,ESModule等多种模块化方式的语法


webpack的模块化原理

在webpack中,一切皆模块。下面我们通过webpack来打包以下代码。通过对打包代码的解析,来一步一步的了解模块化的实现原理。

目录结构如下:


代码如下:

// webpack.config.js
const path = require('path');

module.exports = {
  entry: 'a.js',
  output: {
    path: path.resolve(__dirname, "dist"),
          filename: "[name].js"
    },
    resolve: {
          modules: [path.resolve(__dirname)]
    },
    optimization: {
          minimize: false
    }
}
// a.js
var b = require('b');

module.exports = b.text + ' world';
// b.js
exports.text = 'hello';

在simple目录下执行webpack命令,会在simple目录下生成dist/output.js文件。

// outout.js
// 代码及注释如下

(() => {
  // 所有导入的模块都存储在__webpack_modules__对象中,并且每个模块都要一个标识该模块的id
  var __webpack_modules__ = ({
     847: ((module, __unsed_webpack_exports, __webpack_require__) => {
        // 模块a...
     }),
     996: ((__unused_webpack_module, exports) => {
       // 模块b...
     })
  })
  
  var __webpack_module_cache__ = {};

  function __webpack_require__(moduleId) {
      // 检查缓存中不存在847导出对象,防止模块847多次执行
     if (__webpack_module_cache__[moduleId]) {
        // 从缓存中返回847导出对象
        return __webpack_module_cache__[moduleId].exports;
     }
     
     // 1.创建{exports: {}}对象
     // 2.像缓存中添加该对象,并让该对象与模块id 847相关联
     var module = __webpack_module_cache__[moduleId] = {
       exports: {}
     }
     
     // 3.通过__webpack_modules__查询模块847
     // 4.执行模块847并传入刚刚创建的模块847的导出对象module,以及module.exports等
     __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
     
     // 5.返回模块847的导出对象
     return module.exports;
  }
  
  // 导入模块847
  __webpack_require__(847);
})()

如上代码我们可以知道,所有的的模块都存储在__webpack_modules__对象中,模块的导出对象则存储在__webpack_module_cache__对象中,我们定义的模块都可以通过传入moduleId来调用__webpack_require__接口来访问该模块以及该模块的导出对象。

当我们通过__webpack_require__接口访问模块847的导出对象时。会先判断__webpack_module_cache__对象中有没有该模块的导出对象,如果有的话,则直接返回。如果没有的话则会

(1)创建模块847的导出对象

var module = {
  exports: {}
}

(2)将该导出对象添加到__webpack_module_cache__对象中

__webpack_module_cahce__[moduleId] = module

(3)(4)通过__webpack_modules__查询模块847并执行

// 传入模块847的导出对象,以及require接口
__webpack_modules__[moduleId](module, module.exports, __webpack_require__)

(5)返回模块847的导出对象

return module.exports

图解如下:


橘黄色背景的元素代表数据

绿色背景的元素代表函数


总结

通过模块化的管理方式

每个模块都通过函数封装在自己的局部环境中。 模块与模块之间通过require 接口进行通信。且不用通过暴露在全局环境。

每个模块都明确通过require接口传入依赖的模块,所以模块与模块之间的依赖关系也是非常明了的。如图

a -> b -> c -> d


模块第1次被引用时,调用require接口会像cache中添加导出对象。并返回添加的导出对象。

模块被第2+次引用时,调用require接口查询cache对象时,返回cache中对应的导出对象


本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!

链接: https://fly63.com/article/detial/10144

相关推荐

WebPack中Plugins的使用和整理,以及常用的Plugins插件

Plugins是webpack的基础,我们都知道webpage的plugin是基于事件机制工作的,这样最大的好处是易于扩展。讲解如果扩展内置插件和其他插件,以及我们常用的Plugins插件

Webpack 4正式发布了!

新版 Webpack 中我们所做的每一个更新目的都在于此,为了当大家在使用 Webpack 的时候敏捷连续毫无顿挫感。 webpack 4 进行构建性能测试,得出的结果非常有趣。结果很惊人,构建时间降低了 60%-98%!

大多数项目中会用到的webpack小技巧

webpack技巧的总结:进度汇报、压缩、复数文件打包、分离app文件与第三方库文件、资源映射、输出css文件、开发模式、分析包的大小、更小的react项目、更小的Lodash、引入文件夹中所有文件、清除extract-text-webpack-plugin日志。

什么是webpack?Webpack的核心概念

Webpack已经流行好久了,但很多同学使用webpack时还是一头雾水,一下看到那么多文档、各种配置、各种loader、plugin立马就晕头转向了。我也不例外,以至于很长一段时间对webpack都是一知半解的状态

如何写 Webpack 配置文件

本文从一个小Demo开始,通过不断增加功能来说明webpack的基本配置,只针对新手。webpack基本的配置就可以熟悉了,会引入loader,配置loader选项,会设置alias,会用plugins差不多。

webpack项目轻松混用css module

本文讲述css-loader开启css模块功能之后,如何与引用的npm包中样式文件不产生冲突。比如antd-mobilenpm包的引入。在不做特殊处理的前提下,样式文件将会被转译成css module。

Vue -- webpack 项目自动打包压缩成zip文件

这段时间用 Vue2.0 开发项目,每次打包都会用到 npm run build 命令,但是每次部署时给后端发包都要手动zip压缩,这样一两次还行,但遇到项目板块测试和临时加急功能测试的时候,一天可能就要打包好多次,这就很烦了。

webpack3 升级 webpack4踩坑记录

安装webpack4最新版本;这个在webpack3中,webpack本身和它的CLI是在同一个包中,webpack4中将两个分开管理。记得添加mode用来告知 webpack 使用相应环境的内置优化

Vue中使用webpack别名的方法

Vue中使用webpack别名的方法,需要引入公共文件,但是公共文件的文件路径里当前文件很远,那么就会形成上面示例中的那种路径很长的情况。而因为文件目录是约定俗成的,不可轻易更改,无法修改相对路径。那么该怎么办呢?

通用、封装、简化 webpack 配置

现在,基本上前端的项目打包都会用上 webpack,因为 webpack 提供了无与伦比强大的功能和生态。但在创建一个项目的时候,总是免不了要配置 webpack,很是麻烦。简化 webpack 配置的一种方式是使用社区封装好的库,比如 roadhog。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!