← Назад к вопросам

В чем разница между ESM и CJS?

2.2 Middle🔥 201 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

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

  1. Новые проекты — используй ESM (стандарт ES6)
  2. Фронтенд — ESM (все бундлеры используют ESM)
  3. Backend (Node.js) — ESM для новых проектов, CJS для legacy
  4. Библиотеки — поддерживай оба формата через экспорты
  5. Миграция — инструменты типа cjs-to-esm помогают в переводе

Ключевой вывод: ESM — это будущее JavaScript, так как это официальный стандарт с лучшей оптимизацией, поддержкой tree-shaking и статическим анализом. CommonJS остается для legacy-кода и специфических сценариев на Node.js.

В чем разница между ESM и CJS? | PrepBro