全国客户服务热线
地址:北京市大兴区纪百户街18号
手机:13699656366
电话:010-68001255
企业动态 当前位置: 首页 > 企业动态
【JS】382-JavaScript模块化方案总结

  

【JS】382-JavaScript模块化方案总结(图1)

  微信公众号【前端自习课】和千万网友一起,每日清晨,享受一篇前端优秀文章。

  本文包含两部分,第一部分通过简明的描述介绍什么是 CommonJS、AMD、CMD、UMD、ES Module 以及它们的常见用法,第二部分则根据实际问题指出在正常的 webpack 构建过程中该如何指定打包配置中的模块化参数。

  模块化这个线 之前是不存在的,因此这也被诟病为早期 JavaScript 开发全局污染和依赖管理混乱问题的源头。这类历史渊源和发展概述在本文将不会提及,因此感兴趣可以自行搜索 JavaScript 发展史进行了解。

  CommonJS 的一个模块就是一个脚本文件,通过执行该文件来加载模块。CommonJS 规范规定,每个模块内部,module变量代表当前模块。这个变量是一个对象,它的 exports 属性(即module.exports)是对外的接口。加载某个模块,其实是加载该模块的module.exports属性。

  require命令第一次加载该脚本时就会执行整个脚本,然后在内存中生成一个对象(模块可以多次加载,但是在第一次加载时才会运行,结果被缓存),这个结果长成这样:

  Node.js 的模块机制实现就是参照了 CommonJS 的标准。但是 Node.js 额外做了一件事,即为每个模块提供了一个 exports 变量,以指向 module.exports,这相当于在每个模块最开始,写有这么一行代码:

  模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。

  CommonJS 规范很好,但是不适用于浏览器环境,于是有了 AMD 和 CMD 两种方案。AMD 全称 Asynchronous Module Definition,即异步模块定义。它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。除了和 CommonJS 同步加载方式不同之外,AMD 在模块的定义与引用上也有所不同。

  factory:为模块初始化要执行的函数或对象。如果为函数,它应该只被执行一次。如果是对象,此对象应该为模块的输出值;

  而使用时我们依旧通过 require 关键字,它包含两个参数,第一个数组为要加载的模块,第二个参数为回调函数:

  通过执行该构造方法,可以得到模块向外提供的接口。在与 AMD 比较上存在两个主要的不同点(来自玉伯回答):

  对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。不过 RequireJS 从 2.0 开始,也改成可以延迟执行(根据写法不同,处理方式不同)。CMD 推崇 as lazy as possible.

  UMD,全称 Universal Module Definition,即通用模块规范。既然 CommonJs 和 AMD 风格一样流行,那么需要一个可以统一浏览器端以及非浏览器端的模块化方案的规范。

  先判断是否支持 AMD(define 是否存在),存在则使用 AMD 方式加载模块;

  再判断是否支持 Node.js 模块格式(exports 是否存在),存在则使用 Node.js 模块格式;

  当然,以上说的种种都是社区提供的方案,历史上,JavaScript 一直没有模块系统,直到 ES6 在语言标准的层面上,实现了它。其设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时确定这些东西。比如,CommonJS 模块就是对象,输入时必须查找对象属性。而 ES Modules 不是对象,而是通过export命令显式指定输出的代码。

  ES Modules 的模块化能力由export和import组成,export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。我们可以这样定义一个模块:

  除以上两种命令外,还有一个export default命令用于指定模块的默认输出(一个模块只能有一个默认输出)。如果使用了export default语法,在 import 时则可以任意命Kaiyun官方网站名。由于export default命令的本质是将后面的值,赋给default变量,所以也可以直接将一个值写在export default之后。当然,引用方式也存在多种:

  需要注意的是 Modules 会自动采用严格模式,且 import 命令具有提升效果,会提升到整个模块的头部,首先执行。

  说完理论,来看看实际项目中遇到的问题。当我们开发完一个 JavaScript 模块必然要经历打包的流程,而在 webpack 配置中,通过指定 output 选项就可以告诉 webpack 如何输出 bundle, asset 以及其他载入的内容。那么如何实现不同环境可兼容的构建呢?

  output中有一个属性叫做libraryTarget,被用来指定如何暴露你的模块的属性。你可以这样尝试赋值给一个变量或者指定对象的属性:

  如果需要更完整的模块化 bundle,以确保和各模块系统兼容,那么可以这样尝试:

  因此,如果只看 output 内容,那么我的一个 webpack 生产环境配置可以写成这样:

地址:北京市大兴区纪百户街18号     手机:13699656366    
Copyright © 2026 空间规划服务技术版权所有   
官方公众号二维码展示