JavaScript 模块系统

170 阅读4分钟

在目前的 JavaScript 语言环境中,支持两种系统,即 CommonJS 和 ESM。

ESM 的全拼是 ECMAScript Modules。它是 JavaScript 的一种模块化规范,旨在提供一种标准化的方式来组织和管理代码,使开发者能够更方便地导入和导出模块中的功能、变量和数据。ESM 在 ECMAScript 2015(也称为 ES6)中引入,并被现代浏览器和 Node.js 广泛支持。

CommonJS 和 ESM 的发展历史

CommonJS

  • 起源:CommonJS 规范在 2009 年左右被引入,旨在为 JavaScript 提供一个模块化的解决方案,特别是针对服务器端的 Node.js。它的设计初衷是为了实现模块的同步加载和简单的模块导入导出机制。
  • 特点:CommonJS 使用 require() 函数导入模块,使用 module.exportsexports 对象导出模块。这种设计使得模块之间的依赖关系在运行时动态解析。

ESM (ECMAScript Modules)

  • 起源:ESM 是在 ECMAScript 2015(也称为 ES6)中引入的,旨在为 JavaScript 提供一种更现代化的模块系统。它的设计考虑了浏览器和服务器环境的需求。
  • 特点:ESM 使用 importexport 语法进行模块的导入和导出,支持静态分析和异步加载。这使得 ESM 更适合现代 JavaScript 开发,尤其是在前端应用程序中。

各自的特点

CommonJS

  • 同步加载:CommonJS 模块在运行时同步加载,这意味着当一个模块被导入时,代码执行会被阻塞,直到该模块加载完成。
  • 文件级作用域:每个模块都有自己的作用域,文件内定义的变量不会泄漏到全局作用域。
  • 动态性:允许在运行时根据条件动态加载模块,但这通常不如 ESM 灵活。
  • 环境支持:主要用于 Node.js 环境,浏览器需要通过工具(如 Browserify)转换才能使用。

ESM

  • 异步加载:ESM 模块支持异步加载,这对于现代 Web 应用程序至关重要,可以避免阻塞主线程。
  • 静态分析:ESM 的导入和导出在编译时就可以确定,使得工具能够进行更好的优化(如树摇优化)。
  • 模块级作用域:每个 ESM 模块都有自己的作用域,变量默认是私有的。
  • 广泛支持:ESM 在现代浏览器和 Node.js(从 v12 开始)中得到了广泛支持。

各自的优缺点

CommonJS 优缺点

  • 优点

    • 简单易用,学习曲线较低。
    • 在 Node.js 中得到广泛应用和支持。
    • 模块加载顺序明确,有助于确保所有依赖项都已加载。
  • 缺点

    • 同步加载可能导致性能问题,尤其是在大型应用中。
    • 不支持树摇优化,可能导致较大的打包文件。
    • 不适合客户端开发,因为它需要额外工具来转换。

ESM 优缺点

  • 优点

    • 支持异步加载,提高了性能和响应能力。
    • 支持树摇优化,有助于减少打包文件大小。
    • 更现代化的语法,更易于理解和维护。
  • 缺点

    • 对于旧版 Node.js 的兼容性较差,需要较新的版本才能正常使用。
    • 在某些情况下,与 CommonJS 的互操作性可能会造成困扰。

文件扩展名的定义

  1. .cjs

    • 用途:明确表示该文件使用 CommonJS 模块规范。
    • 特性:在 Node.js 中,.cjs 文件始终被解析为 CommonJS 模块,无论 package.json 中的配置如何。
  2. .mjs

    • 用途:明确表示该文件使用 ECMAScript Modules(ESM)规范。
    • 特性:在 Node.js 中,.mjs 文件始终被解析为 ESM,无论 package.json 的配置如何。
  3. .js

    • 用途:可以是 CommonJS 或 ESM,具体取决于项目的 package.json 配置。
    • 特性
      • 如果在 package.json 中设置 "type": "module",则 .js 文件将被视为 ESM。
      • 如果没有设置或设置为 "type": "commonjs",则 .js 文件将被视为 CommonJS。

.cjs.mjs 是分别用于 CommonJS 和 ESM 的专用文件扩展名,而 .js 文件则根据项目的 package.json 配置决定使用哪种模块系统。这种灵活性使得开发者能够根据需要选择适合的模块化方案,同时也能在同一项目中混合使用这两种模块系统。

总结

CommonJS 和 ESM 是 JavaScript 中两种主要的模块化规范,各自有其独特的发展历史、特点、优缺点。CommonJS 更适合于 Node.js 的传统服务器端开发,而 ESM 则为现代 Web 应用程序提供了更灵活、高效的解决方案。随着 JavaScript 的发展,ESM 正逐渐成为主流选择。