CommonJS、RequireJS 与 ES6 模块:JavaScript 模块化演进史
JavaScript 诞生之初并没有模块化机制。随着应用规模扩大,全局变量冲突、依赖管理混乱等问题日益突出。社区和标准组织先后推出了多种模块化方案,其中最著名的是CommonJS(主要用于服务器端)、AMD / RequireJS(主要用于浏览器端)以及ES6 Module(官方标准)。
CommonJS、RequireJS和ES6 Module是JavaScript模块化发展的三个重要阶段,它们在设计目标、加载机制、语法规范和适用场景上存在本质区别,其中ES6 Module作为官方标准正逐步统一服务器端和浏览器端的模块化开发,本文将从历史背景、核心语法、工作原理和适用场景等方面,厘清这三者的关系与区别。
一、核心概念与设计目标、语法规范
1. CommonJS
- 定位:Node.js默认采用的服务器端模块化标准,设计目标是为非浏览器环境提供标准化库支持
- 适用场景:主要用于服务器端开发,如Node.js应用,涵盖文件系统、I/O流、单元测试等基础功能
- 设计哲学:解决早期浏览器外JavaScript生态缺失问题,为服务端JavaScript提供模块化方案
- 加载机制(CommonJS):
- 同步加载:执行
require()时立即加载并执行模块,后续代码会被阻塞 - 运行时加载:在代码执行阶段才加载模块
- 模块缓存:首次加载后缓存,后续引用直接返回缓存结果
- 同步加载:执行
- 语法规范(CommonJS):
- 导出:
module.exports或exports - 导入:
require() - 代码示例:javascript编辑
- 导出:
// 导出 module.exports = { add: (a, b) => a + b }; // 导入 const math = require('./math'); console.log(math.add(1, 2)); ```<websource>source_group_web_4</websource>2. RequireJS
- 定位:AMD规范的实现,专为浏览器环境设计的模块加载器
- 适用场景:适用于浏览器端复杂Web应用,尤其是需要加载大量JavaScript文件的场景
- 设计哲学:解决传统同步加载方式带来的阻塞问题,实现异步模块加载和依赖管理
- 加载机制(RequireJS):
- 异步加载:
require()发起异步请求加载模块,不阻塞后续代码执行 - 依赖前置:必须提前声明所有依赖模块
- 模块缓存:模块首次加载后会被缓存,后续通过
require()或define()引用同一模块时,直接使用缓存实例,不会重复请求或执行
- 异步加载:
- 语法规范(RequireJS):
- 导出:
define() - 导入:
require() - 代码示例:javascript编辑
- 导出:
// 导出 define([], function() { return { add: (a, b) => a + b }; }); // 导入 require(['math'], function(math) { console.log(math.add(1, 2)); }); ```<websource>source_group_web_5</websource>3. ES6 Module
- 定位:JavaScript官方标准化模块系统,旨在统一服务器端和浏览器端的模块化开发
- 适用场景:既适用于浏览器端也适用于服务器端( Node.js从v13.2.0开始默认支持,必须满足以下任一条件)
- 文件扩展名为
.mjs - 在
package.json中声明"type": "module"
- 文件扩展名为
