Ответ
CommonJS — это стандарт модульной системы, который был основным в Node.js до появления ES Modules. Он использует синхронную загрузку модулей и основан на функциях require() для импорта и module.exports/exports для экспорта.
Базовый пример:
// calculator.js
const add = (a, b) => a + b;
const multiply = (a, b) => a * b;
module.exports = {
add,
multiply
};
// или альтернативно:
exports.add = add;
exports.multiply = multiply;
// app.js
const calculator = require('./calculator');
console.log(calculator.add(5, 3)); // 8
console.log(calculator.multiply(4, 2)); // 8
Ключевые особенности CommonJS:
- Синхронная загрузка: модули загружаются синхронно при первом вызове
require() - Кэширование: модуль загружается только один раз, последующие вызовы
require()возвращают кэшированный экземпляр - Циклические зависимости: поддерживаются, но могут вести себя неочевидно
module.exportsvsexports:exports— это ссылка наmodule.exports, перезаписьexportsновой ссылкой нарушит экспорт
Пример циклической зависимости в CommonJS:
// a.js
console.log('a starting');
exports.done = false;
const b = require('./b.js');
console.log('in a, b.done =', b.done);
exports.done = true;
console.log('a done');
// b.js
console.log('b starting');
exports.done = false;
const a = require('./a.js');
console.log('in b, a.done =', a.done);
exports.done = true;
console.log('b done');
В современных Node.js-проектах я часто использую смешанный подход: CommonJS для конфигурационных файлов и утилит, а ES Modules для основного кода приложения.
Ответ 18+ 🔞
Давай разберем эту тему, а то у некоторых от этих модулей уже глаза на лоб лезут, как у совы на дискотеке.
CommonJS — это, по сути, старый добрый дедушка модульной системы в Node.js, который всех кормил и поил, пока не появились эти ваши модные ES Modules. Работает всё через require(), чтобы подтянуть модуль, и module.exports, чтобы его наружу выдать. Всё синхронно, чинно-благородно, как в советской очереди за колбасой.
Смотри, как это выглядит на практике:
// calculator.js
const add = (a, b) => a + b;
const multiply = (a, b) => a * b;
module.exports = {
add,
multiply
};
// или можно так, но осторожно, тут подвох есть:
exports.add = add;
exports.multiply = multiply;
// app.js
const calculator = require('./calculator');
console.log(calculator.add(5, 3)); // 8
console.log(calculator.multiply(4, 2)); // 8
А теперь главные фишки CommonJS, без которых ты просто манда с ушами:
- Загрузка синхронная — модуль встаёт как вкопанный при первом
require(), и всё ждут, пока он не прогрузится. Никакой асинхронщины, всё по старинке. - Кэширование — модуль грузится один раз, а потом все ходят и пользуются одним и тем же экземпляром, как общей зубной щёткой в общаге. Экономия, бля, хоть куда.
- Циклические зависимости — вроде как работают, но поведение иногда такое, что сам от себя охуеешь. Лучше без этого.
module.exportsпротивexports— вот тут, ёпта, собака зарыта.exports— это просто ссылка, и если её переприсвоить, то всё, пиши пропало, экспорт накрылся медным тазом.
Вот тебе пример, как эти циклы могут мозг вынести:
// a.js
console.log('a starting');
exports.done = false;
const b = require('./b.js');
console.log('in a, b.done =', b.done);
exports.done = true;
console.log('a done');
// b.js
console.log('b starting');
exports.done = false;
const a = require('./a.js');
console.log('in b, a.done =', a.done);
exports.done = true;
console.log('b done');
В общем, в современных проектах часто получается такая сборная солянка: CommonJS оставляем для всяких конфигов и утилит, которые не спешат, а основную логику уже пишем на ES Modules. Главное — не путать и не устраивать в коде ебушки-воробушки из-за непонимания, что куда импортируется.