Arduino-ESP32:物联网设备开发的完整解决方案
2026/7/27 18:15:54
在 Node.js 的生态系统中,存在两种主要的模块规范:CommonJS (CJS)和ES Modules (ESM)。
理解它们的区别对于现代前端和后端开发至关重要,因为 Node.js 正在从 CJS 全面转向 ESM。
CommonJS 是 Node.js 诞生的默认模块系统,已经存在了十多年。
require()导入模块,使用module.exports导出模块。require()时,Node.js 会阻塞后续代码的执行,直到模块加载完成。示例代码:
// 导出 (math.js)constadd=(a,b)=>a+b;module.exports={add};// 导入 (main.js)const{add}=require('./math.js');console.log(add(2,3));ESM 是 JavaScript 在 2015 年(ES6)确立的标准官方模块系统,旨在让浏览器和服务器通用一套标准。
import导入,使用export导出。示例代码:
// 导出 (math.js)exportconstadd=(a,b)=>a+b;// 导入 (main.js)import{add}from'./math.js';console.log(add(2,3));| 特性 | CommonJS (CJS) | ES Modules (ESM) |
|---|---|---|
| 关键字 | require/module.exports | import/export |
| 加载时机 | 运行时加载。 | 编译时加载(静态分析)。 |
| 加载方式 | 同步。 | 异步。 |
| 顶层变量 | 有__dirname,__filename。 | 没有这些变量(需用import.meta.url模拟)。 |
| this 指向 | 指向当前模块。 | undefined。 |
| Tree Shaking | 不支持(因为是动态加载)。 | 支持(可以删除未使用的代码)。 |
| 严格模式 | 默认不开启。 | 强制开启(“use strict”)。 |
import语句必须放在文件顶部。因为它是静态的,打包工具(如 Webpack, Rollup, Vite)可以在代码运行前知道哪些代码被使用了,从而进行Tree Shaking(剔除无效代码),缩小包体积。if语句或函数内部写require()。这使得它很灵活,但也无法在编译阶段进行优化。在 CJS 中,你可以直接使用__dirname获取当前目录。在 ESM 中,这些全局变量不存在,你需要这样操作:
// ESM 获取 __dirname 的方法import{fileURLToPath}from'url';import{dirname}from'path';const__filename=fileURLToPath(import.meta.url);const__dirname=dirname(__filename);现在 Node.js 同时支持两者,判断规则如下:
.cjs总是被视为 CommonJS。.mjs总是被视为 ES Modules。.js取决于最近的package.json。"type": "module",则.js文件被视为ESM。"type": "commonjs"或不设置,则.js文件被视为CJS。import cjs from './file.cjs'通常能工作,但只能默认导入,不能通过解构导入(因为 CJS 是运行时生成的)。require()。因为 ESM 是异步的,而require是同步的。如果必须在 CJS 中用 ESM,只能使用异步的import()函数:// 在 CJS 文件中import('./esm-file.mjs').then(module=>{// 使用模块});