Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
ESM и CommonJS: основные различия
ESM (ECMAScript Modules) и CJS (CommonJS) — это два стандарта модульной системы в JavaScript. Понимание их различий критично для разработки на Node.js и фронтенде.
История и контекст
CommonJS был создан для Node.js в начале 2010-х годов, когда в JavaScript не было встроенной системы модулей. Это динамическая система, рассчитанная на серверную разработку.
ESM — официальный стандарт ES6 (2015), поддерживаемый всеми современными браузерами и Node.js (с версии 14+). Это статическая система модулей, предназначенная для использования везде: браузер, сервер, бандлеры.
Синтаксис
CommonJS
// Импорт
const express = require("express");
const { Router } = require("express");
// Экспорт
module.exports = {
handler: () => {}
};
module.exports.helper = () => {};
ESM
// Импорт
import express from "express";
import { Router } from "express";
// Экспорт
export const handler = () => {};
export default { handler };
export { handler as myHandler };
Ключевые различия
1. Динамичность vs Статичность
CommonJS — динамическая система. Пути модулей могут вычисляться в runtime:
const moduleName = process.env.DEBUG ? "debug-module" : "prod-module";
const module = require(`./${moduleName}`);
// Условный импорт
if (condition) {
const utils = require("./utils");
}
ESM — статическая. Все импорты должны быть определены в начале файла:
// Ошибка: импорты только в начале
if (condition) {
import("./utils"); // Только для динамического импорта (async)
}
// Правильно для статического анализа
import { utils } from "./utils";
if (condition) {
utils.doSomething();
}
2. Синхронность vs Асинхронность
CommonJS — синхронный:
const data = require("./data.json"); // Блокирует до загрузки
ESM — асинхронный на верхнем уровне, для динамических импортов используется Promise:
// Динамический импорт
const module = await import("./module.js");
// Top-level await (в ESM файлах)
await loadData();
3. Область видимости и контекст
CommonJS имеет специальные переменные:
console.log(__filename); // /home/user/app.js
console.log(__dirname); // /home/user
console.log(module.exports); // Текущий объект экспорта
ESM использует import.meta:
console.log(import.meta.url); // file:///home/user/app.js
console.log(import.meta.dirname); // /home/user (Node.js 20.11+)
// Для получения filename/dirname
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
4. Tree-shaking и оптимизация
CommonJS не поддерживает tree-shaking (удаление неиспользуемого кода) из-за динамичности:
const utils = require("./utils"); // Весь модуль загружается
utils.usedFunction();
ESM позволяет бандлерам анализировать и удалять неиспользуемый код:
import { usedFunction } from "./utils"; // Удалится неиспользуемый код
usedFunction();
Практические примеры
Экспорт default vs named
CommonJS:
// math.js
module.exports = {
add: (a, b) => a + b,
subtract: (a, b) => a - b
};
// app.js
const math = require("./math");
math.add(1, 2);
ESM:
// math.js
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
// app.js
import { add } from "./math.js";
add(1, 2);
Совместимость
Использование CommonJS в ESM-проекте:
// import не работает с CJS прямо
// createRequire позволяет использовать require в ESM
import { createRequire } from "module";
const require = createRequire(import.meta.url);
const express = require("express");
Использование ESM в CommonJS-проекте:
// Динамический импорт (async)
const express = await import("express");
Node.js и package.json
CommonJS (по умолчанию):
{
"type": "commonjs",
"main": "index.js"
}
ESM:
{
"type": "module",
"main": "index.js",
"exports": {
".": "./index.js",
"./math": "./math.js"
}
}
Рекомендации в 2024-2026
- Новые проекты — используй ESM (стандарт ES6)
- Фронтенд — ESM (все бундлеры используют ESM)
- Backend (Node.js) — ESM для новых проектов, CJS для legacy
- Библиотеки — поддерживай оба формата через экспорты
- Миграция — инструменты типа
cjs-to-esmпомогают в переводе
Ключевой вывод: ESM — это будущее JavaScript, так как это официальный стандарт с лучшей оптимизацией, поддержкой tree-shaking и статическим анализом. CommonJS остается для legacy-кода и специфических сценариев на Node.js.