CommonJS/AMD/UMD/ES Module介绍和区别

4,663 阅读3分钟

最近在使用Vue开发组件库时,使用lib模式打包之后的文件有xxx.common.js和xxx.umd.js,在这里做一下整理。

1、CommonJS/AMD/UMD/ES Module简介

JavaScript在发展之初,是没有模块化(module)的概念,无法将一个大的程序拆分成相互依赖的小文件,而其他语言比如Java、Python有import,而连CSS都有@import,唯独JavaScript没有。下面我们来看看JavaScript从没有到有模块化概念,在发展过程中经历了哪些阶段。

  • script标签:当时普遍使用一个立即执行的函数,将js代码单独包裹在一个文件里面,然后通过script标签将其进行引入,这样就能使得各自文件的js代码在各自的局部作用域执行,避免相互影响。

  • CommonJS: 后来随着Node.js的出现,就出现了js文件相互依赖的关系,为了解决这个给这个问题,总不能写script标签吧,于是乎就有了Common.js模块依赖的语法,引入使用,let fs = require('fs'),导出使用module.export a =1;。

  • AMD(异步模块定义):由于common.js是同步执行性的,用于服务端,而AMD用于浏览器,他的语法类似CommonJS,具体用法是通过回调,require(‘Vue’,(Vue)=>{new Vue})

  • ESMoudule:上述引入方式并存了一段时间后,制定JavaScript规范的委员会出面,也就是现在的ES6规范,通过import导入JS模块,通过export导出模块,也是用的比较多的一种,现在主流浏览器也基本支持了,在script标签中使用type='module'属性即可。

  • UMD(统一模块定义):这种模块语法,兼容了以上的CommonJS、AMD、ES Module使用方式,也就是Vue脚手lib模式打包的这种模式。

2、CommonJS、AMD、ES Module区别:

  • 在es6之前,社区指定的模块加载方案主要还是CommonJS和AMD两种,前者用于服务器端,后者用于浏览器。而es6使得模块化实现更加简单,可以完全取代CommonJS和AMD规范,成为浏览器和服务端通用的而解决方案

  • ES6模块设计思想是尽量静态化,使得编译 时就确定模块的依赖关系,以及输入输出的变量,Common.js和AMD都是只在运行时,才确定这些关系。

比如Common.js就是对象,输入时必须查找对象属性 

//CommonJS 模块
let {stat, exists, readFile} = require('fs');
 
//相当于
let _fs = require('fs');
let stat = _fs.stat;
let exists = _fs.exists;
let readFile = _fs.readFile;

上述代码的实质是整体加载 fs 模块(即加载 fs 的所有方法),生成一个对象(_fs),然后再从这个对象上读取 3 个方法。这种加载称为 "运行时加载",因为只有运行时才能得到这个对象,导致完全没有办法在编译时进行 "静态优化"。 而 ES6 模块不是对象,它是通过 export 命令显式指定输出的代码,再同构 import 命令输入。 

//ES6 模块
import {stat, exists, readFile} from 'fs';

上述代码的实质是从 fs 模块加载 3 个方法,而不加载其他方法。这种加载称为 "编译时加载" 或者静态加载,即 ES6 可以在编译时就完成模块加载,效率比 CommonJS 的加载方式高。当然,这也导致 ES6 模块本身无法被引用,因为它不是对象。