likes
comments
collection
share

前端模块化:commonJS、AMD、CMD、UMD、ES module

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

概述

历史上,JavaScript 一直没有模块(module)体系,只用一个文件来写程序代码,对于开发维护大型的、复杂的项目是极不友好的。

后来,在社区相继推出了 commonJS、AMD、CMD、UMD、ES module 等模块。

模块介绍

CommonJS

推出时间大约在 2009 年。Node.js 选择了 CommonJS 作为其模块系统,从而使其在服务器端得以广泛应用。它的特性是同步加载模块,在服务器端模块文件都存放在本地磁盘,读取非常快,所以这样做不会有问题。但是,在浏览器端,要从服务器端加载模块,若采用同步加载方式会导致性能、体验等问题

// math.js文件:自定义方法
function add(a, b) {
  return a + b;
}
module.exports = {
  add: add,
};

// index.js文件:引用自定义的模块
var math = require("./math");
math.add(1, 2);

AMD(Asynchronous Module Definition)

推出时间大约在 2011 年。其主要应用场景是浏览器端,异步加载模块,与 CommonJS 最大的不同在于,AMD 采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖某些模块的语句均放置在回调函数中。知名的库有 require.js

// 导入模块
require(["module1", "module2"], function (module1, module2) {
  //使用导入的模块
});

// 定义模块
define(["dependency"], function (dependency) {
  return moduleName;
});

CMD(Common Module Definition)

推出时间大约在 2012 年。同样是为了解决浏览器端的模块化问题,CMD 相比 AMD 使用的是依赖就近,延迟执行等特性,写代码的时候哪里使用哪里再引入模块。知名的库有 sea.js

// 定义导出模块 math.js
define(function (require, exports, module) {
  var $ = require("jquery.js");
  var add = function (a, b) {
    return a + b;
  };
  exports.add = add;
});
// 在需要使用的地方就近导入模块
seajs.use(["math.js"], function (math) {
  var sum = math.add(1 + 2);
});

UMD(Universal Module Definition)

推出时间大约在 2013 年。UMD 主要是解决跨平台模块化方案的问题,它合并了 CommonJS 和 AMD 规范,能够兼容各种情况的环境,同时运行在客户端和服务器端,因此被称为是通用的模块定义。当使用 Rollup/Webpack 之类的打包器时,UMD 通常用作备用模块

(function (root, factory) {
  if (typeof define === "function" && define.amd) {
    define(["dependency"], factory);
  } else if (typeof exports === "object") {
    module.exports = factory(require("dependency"));
  } else {
    root.returnExports = factory(root.dependency);
  }
})(this, function (dependency) {
  return {}; //返回值即为定义的模块
});

ES module

推出时间为 2015 年。ES6 或更高版本在语言标准层面上实现了模块功能,解决了 JavaScript 文件无法使用import, export命令,在语法层面上对模块进行了支持,标准化产品,使得 JavaScript 模块化具备了规范性。可以直接运行在现代浏览器中,也可以作为服务器端模块使用

// 导出模块
export default SomeObject;
// 导入模块
import moduleName from "./module";

优缺点对比

模块优点缺点
CommonJS服务器端模块,同步加载,写法简单直观;Node.js选择了CommonJS作为其模块系统,使其在服务端得以广泛应用。无法直接在浏览器中运行,需通过如Browserify的工具转换;同步加载可能导致性能问题,特别是处理大型、复杂的依赖树时。
AMD解决了浏览器环境下模块的异步加载问题,特别在处理大型、复杂的依赖树时有较好性能;可以并行加载多个模块。代码的阅读和书写比较困难
CMDCMD规范和AMD规范类似,但是依赖就近,延迟执行,只需要简单的define函数。CMD规范和AMD规范类似,非官方标准,需要运行在如Sea.js之类的运行库上。
UMDUMD模块格式被设计成可以在CommonJS和AMD两个最常见的JavaScript模块定义格式之间进行切换;能够在几乎所有的JavaScript运行环境下执行。UMD的代码结构略显复杂
ES ModuleES Module是JavaScript官方标准,出色的静态模块结构使得编译时就能确定模块的依赖关系,也有助于静态分析和Tree Shaking等优化;浏览器原生支持,无需引入库或者构建工具进行转换,使用简便。一些旧版浏览器并不支持ES Module。

总结

  • 由于ES module的设计思想是尽量的静态化,使得代码可以静态分析和tree shaking等优化,是目前最好的模块化方案
  • UMD 用得很广泛,通常在 ESM 不起作用的情况下用作备用
  • CJS 是同步的,适合服务端
  • AMD/CMD 是异步的,适合用户端

参考文献

es6.ruanyifeng.com/#docs/modul…

dev.to/iggredible/…