CommonJS和ES Modules篇

CommonJS和ES Modules篇

1、认识

CommonJS(CJS)ES Modules(ESM) 是JS的两种模块化系统。在模块导入、导出、加载机制、使用场景等方面存在显著的区别。

🍎模块化发展历程

2009 => CommonJS 诞生,被Node.js作为一个标准开始制定使用,作为默认的模块化系统

2010年 =>CommonJS 模块规范正式发布

2015 => ES6 Modules 标准化,同年也是ECMAScript 6(即 ES6)规范的发布

2020 => Node.js 13+ 正式支持 ES Modules

2023 => 90% 的新项目首选 ES Modules

🍎使用场景以及支持的环境

CommonJS

主要用于 Node.js 环境,虽然在浏览器中能通过工具(如 Webpack、Browserify)进行打包,但原生不支持。

ES Modules

浏览器和 Node.js 都支持 ES Modules,且现代浏览器普遍支持 <script type="module"> 标签。

🍎语法区别

CommonJS

CommonJS 是一种同步加载模块的规范,主要用于服务器端的 JavaScript(比如 Node.js)。

plain 复制代码
// 导入模块
const module = require('xxx');


//导出模块
module.exports = { xxx };

或者使用下面的写法

plain 复制代码
exports.xxxFunction = function() { 
    xxx
};
ES Modules

ES Modules是 JavaScript 官方标准(ECMAScript)的一部分,旨在在浏览器和服务器端(如 Node.js)中提供一致的模块化支持。

plain 复制代码
// 导入模块 方式一 (推荐使用)
import { someFunction } from './module-name';

// 导入模块 方式二
import * as module from './xxx';
plain 复制代码
// 导出模块 方式一(推荐使用)
export const someFunction = () => { };

// 导出模块 方式二
export default function() {  };

2、CommonJS和ES Modules发展及解决问题

2009以前

JavaScript 初期,浏览器环境中的 JavaScript 程序通常是单一的、全局作用域的,所有代码都混合在一起。程序复杂以后,开发者的代码急切的需要一种模块化机制来组织代码、提高可重用性和可维护性

为了应对 Node.js 环境中对模块的需求,Node.js(2009年发布)使用了CommonJS作为默认的模块化系统,Node.js制定标准CommonJS,2010年CommonJS模块正式发布。

CommonJS 模块是同步加载的,使得它适用于服务器端应用。

但CommonJS 模块是在运行时加载的,导致无法进行静态分析,像 Tree Shaking 和 代码分割(Code Splitting) 这样的优化无法在打包时进行

2015年ECMAScript 6(即 ES6)规范发布,内建模块系统ES Modules(ESM),ES6 Modules 彻底标准化。ESM 的静态结构使得 JavaScript 引擎能够在编译时进行优化,Tree Shaking 和 代码分割(Code Splitting)信手拈来,并且**跨平台支持。**2020年Node.js 13+ 全力支持 ES Modules,ESM成为主流。

3、CommonJS和ESM的区别和不同

🍎加载方式的区别

CommonJS同步加载,当执行 require() 时,Node.js 会立即加载并执行模块代码。加载后的模块被缓存,并且返回模块的导出对象。适合于服务器端的同步需求。

CommonJS不能在浏览器中直接使用(直到现代浏览器支持 ES Modules)

ES Modules是异步加载 的,适用于浏览器和服务器端

支持静态分析,编译器和打包工具可以提前分析模块的依赖关系

支持动态导入,使用 import() 函数异步加载模块

涉及到按需加载和优化性能时非常好用

🍎模块的解析和执行时机

CommonJS模块代码立即执行,当 require() 被调用时,模块会立即被加载并执行一次

ESModules模块代码按需加载,模块的导入是静态绑定,导入的值是模块首次执行时的值,且不再变化

🍎默认导出

CommonJS使用 module.exports 进行导出,默认导出的模块对象不需要特别标注

plain 复制代码
// CommonJS 导出
module.exports = function() { /* ... */ };

ES Modules支持 default 导出,直接导出一个默认值

plain 复制代码
// ES Modules 导出
export default function() { /* ... */ };

🍎模块缓存

CommonJS在第一次被 require() 时会被加载并缓存,后续的 require() 调用将直接返回缓存的模块对象

ES Modules也会被缓存,但每个模块导入时,它是只读的,按照静态结构导出,不会改变

🍎在 Node.js的支持

CommonJS

Node.js 原生支持 CommonJS,从 Node.js 的最早版本开始就被广泛使用

ES Modules

在 Node.js 中,从 v12.x 开始引入对 ES Modules 的支持,但需要使用 .mjs 文件扩展名或通过 "type": "module" 配置项启用对 ESM 的支持。

到 Node.js 14 版本,ESM 才逐渐变得更加稳定和广泛使用。

🍎循环依赖处理

CommonJS

CommonJS 处理循环依赖时,返回的是已加载的模块的部分内容,这可能导致循环依赖的一些问题。

ES Modules

ESM 通过 "死锁" 模式来处理循环依赖,确保模块的内容始终是稳定和一致的。

4、两者对比

特性 CommonJS ESModule (ESM)
加载方式 同步加载 异步加载(支持动态导入) 支持懒加载
模块语法 require() module.exports import export
跨平台兼容性 主要适用于 Node.js,浏览器需使用工具支持 浏览器和 Node.js 都支持
导出类型 无法区分默认导出与命名导出 支持默认导出 (export default
模块缓存 会缓存已加载模块 缓存且模块是只读的
循环依赖处理 可能会返回部分模块 更好地处理循环依赖
适用 服务器端的同步加载和模块化 现代的前端开发和浏览器环境
优点 兼容性良好、同步加载、简单易用 支持异步加载、静态分析和更清晰的模块结构
静态分析和优化 无法进行静态分析,不能进行优化 支持静态分析 支持Tree Shaking (去除未使用的代码) 代码分割(Code Splitting)
性能 较为适合服务器端,浏览器中性能较差 支持懒加载和优化,适用于浏览器和 Node.js
生态系统 已有庞大的生态系统,几乎所有 Node.js 包都使用 生态系统逐步成长,尤其是在现代 JavaScript 项目中
互操作性 与其他模块系统兼容良好 与 CommonJS 存在兼容性问题
支持的 Node.js 版本 所有 Node.js 版本均支持 Node.js 从 v12 开始全面支持 ESM
错误处理与模块执行顺序 顺序执行,无异步问题 模块执行有异步加载的潜在影响
学习曲线 简单,易于上手 对于老旧项目的迁移可能需要更多工作
**顶层 ****await**支持 不支持 支持
相关推荐
花菜会噎住3 分钟前
Vue3核心语法进阶(生命周期)
前端·javascript·vue.js·生命周期
西岭千秋雪_7 分钟前
前端工程化:ES6特性
前端·javascript·ecmascript·es6
样子201819 分钟前
PHP 之使用HTMLPurifier过滤XSS
开发语言·前端·php·xss
小阿鑫23 分钟前
程序员最强外设,这才是Coding该有的样子!
前端·程序员·显示器·设计·最强外设
Godiswill25 分钟前
三款简洁免费 AI 抠图去背景网站
前端·javascript·人工智能
haruma sen1 小时前
Spring面试
java·spring·面试
素界UI设计2 小时前
开源网页生态掘金:从Bootstrap二次开发到行业专属组件库的技术变现
前端·开源·bootstrap
潘小安2 小时前
【译】六个开发高手使用的 css 动画秘诀
前端·css·性能优化
前端开发爱好者2 小时前
尤雨溪官宣:Vite 历史性的一刻!超越 Webpack!
前端·javascript·vite
前端开发爱好者2 小时前
Vue3 "抛弃" Axios !用上了 专属请求库!
前端·javascript·vue.js