在看 Babel 的时候,里面介绍了四种模块化的插件,AMD、Commonjs、SystemJS、UMD,还有 CMD、EMS 没有涉及,在这里总结一下调查的内容。
目前使用的模块化协议有 AMD、CMD、CommonJS、UMD、SystemJS、ESM
AMD(Asynchronous Moudle Definition)异步模块定义;CMD(Common Module Definition)通用模块定义;它们都是一种在浏览器端模块化开发的规范,并没有被JS原生支持。
在使用AMD 规范进行页面开发,需要使用到对应的 RequireJS 库函数,实际上 AMD 也是 RequireJS 在推广过程中对模块定义的规范化的产出。
Require.js 官网 https://requirejs.org/
在使用CMD 规范进行开发,用到的是 SeaJS 库函数,它是国内发展出来的。
Sea.js 官网 https://seajs.github.io/seajs/docs/
看了两个官网样式,都有历史的味道。
例子🌰:
// 引入 require.js
// 定义 myModule.js 模块
define(['dependency'], function() {var name = "Byron";function printName() {console.log(name);}return {printName: printName}
});//加载模块
require(['myModule'], function(my) {my.printName();
})
语法:
Require.js 定义全局函数 define 用来定义模块,require 加载模块
id 定义模块标识符,默认是脚本文件名(去除扩展名)
dependencied 当前模块依赖的模块名称数组
factory 模块初始化执行的函数或对象,函数之被执行一次,对象是为模块的输出值
dependencies 依赖的模块
callback 回调函数,在指定模块加载完成后被调用
require() 函数在加载以来的函数是异步加载,指定的回调函数,在前面模块都加载完成后才会运行。
例子🌰:
// 引入 Sea.Sea
// 定义模块 myModule.js
define(function(require, exports, module) {var math = require('math');exports.add = function(left, right) {return math.add(left, right);}
});// 加载模块
require(['myModule'], function(my) {console.log(my.add(1, 1));
})
CMD 推崇的是依赖就近,所以一般不在 define 的参参数写依赖
id 定义模块标识符,默认是脚本文件名(去除扩展名)
dependencied 当前模块依赖的模块名称数组
factory 回调函数的参数有三个:
require 接受模块标识,用来获取其他模块提供的接口
exports 用来向外提供模块的对象
存储当前模块信息的对象
在浏览器中使用
明显的区别在于模块定义时候依赖的处理方式:
这种区别只是在语法上的差距。实现库 Require.js 和 Sea.js 都支持对方的写法。
在服务器使用
这个规范在 Node 中被原生支持
协议 https://www.commonjs.org/
协议规范,一个单独的文件就是一个模块,每个模块都是一个单独的作用域。达到的效果就是咋模块内部定义的变量是无法被其他模块读取的,除非是定义为 global 对象的作用域。
通过 exports 和 module.exports 来暴露模块内容
通过 require 来加载模块
例子🌰:
通过 exports 暴露
// 模块定义
var hello = function () {console.log('hello studygd.com.');
}
exports.hello = hello;// 模块加载
const studygd = require('./study');
studygd.hello();
通过 module.exports 暴露
module.exports = {add: function(left, right) {return left + right;},subtract: function(left, right) {return left - right;}
}
上面已经介绍的协议实现上 AMD、CMD 被限制在浏览器中使用,CommonJS 被限制在服务端使用,两种协议的不同必然带来复用问题,UMD 解决了这个问题。
根据官网介绍,它是使用了 AMD 作为基础,添加了包裹函数来处理 CommonJS 的兼容性。
Github 地址 https://github.com/umdjs/umd
例子🌰:
(function (global, factory) {if (typeof define === "function" && define.amd) {// amddefine(["exports"], factory);} else if (typeof exports !== "undefined") {factory(exports);} else {// commonjsvar mod = {exports: {}};factory(mod.exports);global.test_umd = mod.exports;}
})(typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : this, function (_exports) {"use strict";Object.defineProperty(_exports, "__esModule", {value: true});_exports.default = void 0;var _default = 42;_exports.default = _default;
});
诞生于 2015 年,那时候 ES Module 还没有成熟,已经开始使用 require.js 和 sea.js,system.js 为了做一个通用的模块加载器应运而生。
SystemJS 是目前浏览器(浏览器尚未正式支持 importMap)原生 ES Module 的替代品,把 ES Module 编译成 System.register 格式然后运行在旧版本的浏览器中。
引入模块方式,例子🌰:
// 通过标签引入 moment 和 lodash 模块
// 因为大部分浏览器不支持(也就 chrome 支持) importmap 需引入额外的库做兼容
内部解析,例子🌰:
// ESM 方式
export default 42;
// Babel 中给出的转换成 SystemJS 协议的产物
System.register([], function(_export, _context) {return {setters: [],execute: function() {_export("default", 42);},};
});
是 ECMAScript 标准化的模块化协议,目前已经被浏览器和 Node 6+ 中支持
通过 export 导出,import 导入,这应该是我平时接触的最多的场景了。
介绍的内容都是作为粗略了解,大部分还没遇到使用场景,先记一下。