主要记录了前端项目中Commonjs、AMD、 CMD、ESmodule模块化区别及特点。
模块化
在没有模块化之前可以通过立即函数调用表达式(IIFE)来解决,命名冲突等问题。
<u>模块化规范的出现主要解决以下问题:</u>
- 多人协作开发中没有规范的混乱场景,避免命名冲突及全局混淆
- 便于代码的组织、拆分及复用
- 采用模块化类库规范项目管理进行模块化开发
- Browserify
- Gulp
- Grunt
- Webpack
- ...
服务端的模块化
Commonjs
开始于一个ServerJS项目提出的用于服务端的模块化规范,后为了体现其广泛性更改为Commonjs,也简称为CJS。
- 使用exports、module.exports导出
- 使用require导入。
js
// 设置主文件
seajs.use('./index.tsx');
// 配置
seajs.config({
base: '/', // 基础路径
alias: { // 模块别名
jquery: './lib/jquery'
},
paths: { // 路径别名
bar: './bar'
}
})
// 定义模块foo.js
define(function(require, exports, module) {
// 也可以使用条件异步加载
if (flag) {
require.async('bar/bar.js', function() {
})
}
module.exports = {
foo: 'xxx'
}
})
// 使用模块index.js
define(function(require, exports, module) {
var foo = require('./foo.js');
})
特点
- 兼顾了浏览器异步记载和Nodejs的书写规范
- 依赖的自动加载和配置使得项目的配置关联度更高,加上插件社区能很好满足当时时期的开发需求
UMD(Universal Module Definition)
是对AMD和CMD规范的整合规范写法.
js
// 定义一个可以同兼容amd/commonjs的模块
(function (global, factory) {
// AMD
if (typeof define === 'function' && define.amd) {
define(['xxx'], factory);
}
// Node/CommonJS
else if (typeof module === 'object' && module.exports) {
module.exports = factory();
}
// window
else {
global['xxx'] = factory();
}
}(window, function () {
// return ...;
}));
而且不管 AMD、CMD 还是 CommonJS 都没有统一浏览器和客户端的模块化规范。
由此ECMAScript官方提出一个标准的模块加载方式: ESModule
ES Module
- export、export default导出
- import xxx from 'xxx' 或 import()导入
js
// badge.js
export var name = 'xxx';
// 异步导入
if (flag) {
import('../modules/foo').then(res => console.log(res))
}
// index.tsx
import { name } from './badge.js';
特点
- 现代浏览器的支持,不支持版本可使用systemjs兼容
- 静态解析,便于构建工具执行前的优化操作,但不能在条件中引入可以使用动态引入
- 异步加载并且实时绑定, export导出时会创建模块环境记录(module environment record)
- Nodejs9+也支持了ES Module 需要将后缀改为.mjs
commonjs和esmodule交互
- 通常情况下,CommonJS不能加载ES Module
- 因为CommonJS是同步加载的,但是ES Module必须经过静态分析等,无法在这个时候执行JavaScript代码;
- 但是这个并非绝对的,某些平台在实现的时候可以对代码进行针对性的解析,也可能会支持;
- Node当中是不支持的;
- 多数情况下,ES Module可以加载CommonJS
- ES Module在加载CommonJS时,会将其module.exports导出的内容作为default导出方式来使用;
- 这个依然需要看具体的实现,比如webpack中是支持的、Node最新的Current版本也是支持的;
- 但是在最新的LTS版本中就不支持;