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

Какие существуют системы модульности в Node.js?

1.8 Middle🔥 151 комментариев
#Node.js и JavaScript#Архитектура и паттерны

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

🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)

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

Системы модульности в Node.js

Node.js поддерживает несколько систем для организации кода в модули. Давайте разберём каждую из них, их особенности, преимущества и недостатки.

1. CommonJS (CJS)

CommonJS — это оригинальная система модулей Node.js, разработанная специально для серверной стороны.

Синтаксис:

// Экспорт
module.exports = {
  sayHello: () => console.log("Hello"),
  add: (a, b) => a + b
};

// Или частичный экспорт
module.exports.sayHello = () => console.log("Hello");

// Импорт
const math = require("./math");
const { add, sayHello } = require("./math");

sayHello();
console.log(add(2, 3)); // 5

Характеристики:

  • Синхронная загрузка — модули загружаются сразу
  • Динамическое подключение — можно использовать require внутри условий
  • Кэширование — модули кэшируются после первого импорта
  • Циклические зависимости — частично поддерживаются

Пример кэширования:

// module.js
let counter = 0;
module.exports = {
  increment: () => ++counter,
  getCounter: () => counter
};

// app.js
const mod1 = require("./module");
const mod2 = require("./module");

mod1.increment();
console.log(mod2.getCounter()); // 1 (один экземпляр)

2. ES Modules (ESM)

ESM — это стандартная система модулей JavaScript, поддерживаемая во всех современных окружениях.

Синтаксис:

// Экспорт (именованный)
export const sayHello = () => console.log("Hello");
export const add = (a, b) => a + b;

// Экспорт по умолчанию
export default {
  sayHello: () => console.log("Hello"),
  add: (a, b) => a + b
};

// Импорт
import { sayHello, add } from "./math.js";
import utils from "./math.js";

// Динамический импорт
const module = await import("./math.js");

// Импорт всего как объект
import * as math from "./math.js";

Характеристики:

  • Асинхронная загрузка — модули загружаются асинхронно
  • Статический анализ — зависимости определяются на этапе парсинга
  • Кэширование — каждый импорт возвращает один экземпляр
  • Циклические зависимости — лучше обрабатываются благодаря временным мёртвым зонам (TDZ)
  • Top-level await — можно использовать await на верхнем уровне модуля

Включение ESM в Node.js:

{
  "type": "module",
  "name": "my-app"
}

Или использовать расширение .mjs:

node app.mjs

3. AMD (Асинхронное определение модулей)

AMD не используется в Node.js, это решение для браузера (RequireJS), но полезно знать.

// Редко используется в Node.js
define(["./math"], function(math) {
  return {
    calculate: () => math.add(2, 3)
  };
});

4. UMD (Универсальное определение модулей)

UMD объединяет CommonJS и AMD, позволяя работать как в Node.js, так и в браузере.

(function(root, factory) {
  if (typeof module === "object" && module.exports) {
    module.exports = factory();
  } else if (typeof define === "function" && define.amd) {
    define([], factory);
  } else {
    root.myModule = factory();
  }
}(typeof self !== "undefined" ? self : this, function() {
  return {
    sayHello: () => console.log("Hello")
  };
}));

Сравнение систем

ХарактеристикаCommonJSESM
ЗагрузкаСинхроннаяАсинхронная
Анализ зависимостейДинамическийСтатический
Поддержка в Node.jsВстроенаТребует "type": "module"
Tree-shakingНе поддерживаетПоддерживает
Top-level awaitНетДа
ПроизводительностьБыстрее на стартеЛучше с бандлерами

Совместимость CommonJS и ESM

Node.js позволяет импортировать CommonJS модули в ESM, но не наоборот:

// ESM модуль может импортировать CJS
import cjs from "./math.cjs";

// CJS модуль НЕ может импортировать ESM
// require("./math.mjs"); // Ошибка!

Лучшие практики

1. Используй ESM для новых проектов

  • Стандарт индустрии
  • Лучшая поддержка в инструментах
  • Более производительный с бандлерами

2. Структурируй модули по функциям

// src/
// ├── users/
// │   ├── user.model.js
// │   ├── user.service.js
// │   ├── user.controller.js
// │   └── index.js
// ├── posts/
// └── app.js

3. Используй индексные файлы для экспорта

// src/users/index.js
export { UserService } from "./user.service.js";
export { User } from "./user.model.js";

4. Избегай циклических зависимостей

// ❌ Плохо
// a.js: import b from "./b.js";
// b.js: import a from "./a.js";

// ✅ Хорошо — используй отдельный модуль
// shared.js: export const helper = ...
// a.js: import { helper } from "./shared.js";
// b.js: import { helper } from "./shared.js";

Дополнительные инструменты

  • Bundlers: Webpack, Vite, esbuild — объединяют модули для браузера
  • Package managers: npm, yarn, pnpm — управляют зависимостями
  • Module resolution: Node.js использует алгоритм поиска модулей в node_modules

Заключение

Современный Node.js разработчик должен хорошо понимать обе системы: CommonJS для наследуемого кода и ESM для новых проектов. В большинстве случаев ESM — это правильный выбор благодаря стандартизации и лучшей поддержке инструментами.

Какие существуют системы модульности в Node.js? | PrepBro