前言
ESM(ECMAScript Modules)和 CJS(CommonJS)是 JavaScript 的两种模块系统:
CJS(CommonJS)
- Node.js 传统模块系统。
- 使用 require() 导入,module.exports 导出。
- 同步加载,适合服务器端。
- 动态加载(可在条件语句中使用)。
ESM(ECMAScript Modules)
- JavaScript 官方标准(ES6+)。
- 使用 import / export。
- 静态结构(必须在顶层),支持 tree-shaking。
- 浏览器原生支持,Node.js 需启用(如设 “type”: “module”)。
- 导出的是实时只读绑定,非值拷贝。
简记:
CJS 是 Node 旧标准,动态同步;ESM 是现代标准,静态异步,更适合前端和NodeJS以后的开发。
Web前端推荐使用ESM。
NodeJS推荐使用ESM或CJS。
ESM
在ES6中,我们可以使用 import 关键字引入模块,通过 exprot 关键字导出模块,功能较之于前几个方案更为强大,也是我们所推崇的。
导出/导入
导出
1 | export const A = 42; |
导入
导入变量/方法的时候变量和方法名必须和导出时一致
1 | import { A,api,myfunc,myapi,MyClass } from './A' |
import导入的变量都是只读的,加载后不能修改
1 | import { m } from 'my_module'; |
默认-导出/导入
注意default一个文件只能有一个
导出
1 | export default "http://www.psvmc.cn"; |
导入
导入默认时变量和方法名可自定义
1 | import A from './A' |
全部导出/导入
全部导出
1 | export * from "module" |
export * from "module"不包含default导出,但export * as ns from "module"(在ns上)是包含default导出的。
全局导入
1 | let m1 = 1; let m2 = 2; export {m1, m2}; |
导入
1 | import * as mynum from '@/assets/js/Test' |
注意
导出的默认不能直接通过
console.info(mynum);打印。
直接打印的化结果如下:
页面中使用
报错
Uncaught SyntaxError: Cannot use import statement outside a module
方式1(不建议 学习的时候可以这样)
HTML中直接用要添加type="module"
1 | <script type="module"> |
方式2 通过webpack打包
但是由于ES6目前无法在浏览器中执行,所以,我们只能通过babel将不被支持的import编译为当前受到广泛支持的 require
解决方法:在项目中配置webpack即可
CommonJS(NodeJS)
前端浏览器不支持,用于服务器,Nodejs中使用的是这个规范
导出
1 | exports.area = function(r) { |
CommonJS的核心思想就是通过 require 方法来同步加载所要依赖的其他模块,然后通过 exports 或者 module.exports 来导出需要暴露的接口。
导入
1 | const { area } = require("area"); |
AMD/CMD
AMD
浏览器端的模块,不能采用后端使用的CommonJS的”同步加载”(synchronous),只能采用”异步加载”(asynchronous),这就是AMD规范诞生的背景。
AMD是RequireJS在推广过程中对模块定义的规范化产出。
AMD规范则是非同步加载模块,允许指定回调函数。
AMD标准中,定义了下面两个API:
- require([module], callback)
- define(id, [depends], callback)
即通过define来定义一个模块,然后使用require来加载一个模块。
require还支持CommonJS的模块导出方式。
test.js
1 | define(['package/lib',...], function(lib) { |
CMD
CMD是SeaJS在推广过程中对模块定义的规范化产出。
CMD是同步模块定义。
1 | //所有模块都通过define来定义 |
二者的区别是前者是对于依赖的模块提前执行,而后者是延迟执行。
前者推崇依赖前置,而后者推崇依赖就近,即只在需要用到某个模块的时候再require。