Learning Book

CommonJS vs ESM

CommonJS vs ESM

CommonJS (CJS) — система модулей Node.js, появившаяся задолго до стандарта ESM. Их различия важны при написании библиотек и настройке сборки.

Синтаксис

// CommonJS
const fs = require('fs')                    // импорт
const { readFile } = require('fs')          // деструктуризация

module.exports = { myFunc, MyClass }        // экспорт объекта
module.exports = myFunc                     // экспорт функции
exports.helper = () => { ... }             // добавление к exports

// ESM
import fs from 'fs'                         // default импорт
import { readFile } from 'fs'              // named импорт
import * as fsAll from 'fs'               // namespace импорт

export function myFunc() { ... }            // named export
export default MyClass                      // default export

Ключевые различия

ХарактеристикаCommonJSESM
ЗагрузкаСинхроннаяАсинхронная
АнализДинамический (runtime)Статический (parse time)
ЭкспортыКопии значенийЖивые привязки
this в верхнем уровнеmodule.exportsundefined
__dirname, __filenameДоступныНедоступны (используй import.meta.url)
Расширение.js (в Node.js по умолчанию).mjs или "type": "module" в package.json
// В ESM нет __dirname — используй import.meta
import { fileURLToPath } from 'url'
import { dirname } from 'path'

const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)

Интероперабельность

// ESM может импортировать CJS (Node.js 12+):
import cjsModule from './legacy.cjs'  // только default import!

// CJS НЕ МОЖЕТ require() ESM:
const esm = require('./modern.mjs')   // Error: require() of ES Module

// CJS может использовать ESM через динамический импорт:
async function loadEsm() {
  const { myFunc } = await import('./modern.mjs')
  return myFunc()
}
При написании библиотеки в 2024+ году: пиши в ESM, добавляй поле "exports" в package.json с CJS-версией через "require" для обратной совместимости. Инструменты типа tsup/rollup умеют автоматически генерировать оба формата.

package.json: объявление типа модулей

{
  "type": "module",
  "exports": {
    ".": {
      "import": "./dist/index.mjs",
      "require": "./dist/index.cjs"
    }
  }
}