В этом руководстве вы узнаете о модулях Node.js и CommonJS и поймете, как они работают.
Node.js по умолчанию поддерживает модульную систему, называемую модулями CommonJS. Начиная с версии 14.0.0 он поддерживает модули ES. В этом руководстве основное внимание уделяется модулям CommonJS.
В модулях рассматривает каждый файл JavaScript как отдельный модуль.
Давайте разберем простой пример, чтобы увидеть, как модули работают в Node.js.

Создание нового модуля
Сначала создайте новый файл с именем logger.js со следующим кодом:
const error = 'ERROR';
const warning = 'WARNING';
const info = 'INFO';
function log(message, level = info) {
console.log(`${level}: ${message}`);
}
logger.js содержит три константы и функцию.
Функция log() в модуле logger принимает два параметра: message и level. Если вы не передаете level в функцию log(), по умолчанию используется info.
В модуле logger.js все переменные и функции являются приватными. Это означает, что они невидимы и не могут использоваться в других модулях.
Чтобы использовать переменные и функции модуля в другом модуле, вам необходимо экспортировать их в конец файла logger.js :
module.exports.log = log; module.exports.error = error; module.exports.info = info; module.exports.warning = warning;
Этот код создает новые свойства объекта module.exports и назначает их соответствующим переменным и функциям.
Также вы можете использовать разные имена при экспорте объектов. Например:
module.exports.fatal = error;
В этом случае другие модули будут ссылаться на константу error как на fatal константу.
Теперь вы готовы использовать функцию log() и все константы модуля logger в другом модуле.
Импорт
Во-вторых, создайте новый файл с именем app.js, который использует модуль logger.js. Чтобы использовать модуль logger.js из app.js, вам необходимо импортировать модуль logger с помощью функции require() :
const logger = require('./logger.js');Или вы можете удалить расширение .js из logger.js следующим образом:
const logger = require('./logger');Незаметно функция require() выполняет файл logger.js и возвращает объект exports. Если функция require() не может найти файл, она выдаст ошибку.
Ниже показаны объекты logger для консоли:
const logger = require('./logger');
console.log(logger);Выход:
{
log: [Function: log],
error: 'ERROR',
info: 'INFO',
warning: 'WARNING'
}Объект logger содержит функцию log() и другие константы из модуля logger.js. Вы можете ссылаться на них следующим образом:
const logger = require('./logger');
logger.log('Node.js module demo 1');
logger.log('Node.js module demo 2', logger.warning);Выход:
INFO: Node.js module demo 1 WARNING: Node.js module demo 2
Чтобы сделать код более лаконичным, вы можете использовать деструктуризацию объекта при импорте модуля следующим образом:
const { log, error, info, warning } = require('./logger');Деструктуризация объекта присваивает свойства объекта exports, возвращаемого функцией require(), переменным с левой стороны.
После деструктуризации вы можете напрямую использовать эти переменные:
log('Node.js module demo 1');
log('Node.js module demo 2', warning);Выход:
INFO: Node.js module demo 1 WARNING: Node.js module demo 2
Понимание модуля функции-оболочки
Прежде чем Node.js выполнит модуль, он оборачивает весь код внутри этого модуля с помощью функции-оболочки, которая выглядит следующим образом:
(function(exports, require, module, __filename, __dirname) {
// Module code
});Например, код модуля logger.js перед выполнением будет выглядеть так:
(function(exports, require, module, __filename, __dirname) {
const error = 'ERROR';
const warning = 'WARNING';
const info = 'INFO';
function log(message, level = info) {
console.log(`${level}: ${message}`);
}
module.exports.log = log;
module.exports.error = error;
module.exports.info = info;
module.exports.warning = warning;
});Делая это, Node.js достигает следующих важных целей:
- Удержание переменных верхнего уровня (
var,letиconst) привязанными к модулю, а не к глобальному объекту. - Создание некоторых специфичных для модуля переменных, таких как глобальные переменные, например
moduleиexports.
Обратите внимание, что объект exports ссылается на module.exports :
console.log(module.exports === exports); // true
Импорт одного и того же модуля несколько раз
Когда вы используете функцию require() для включения модуля несколько раз, функция require() оценивает модуль только один раз при первом вызове и помещает его в кеш.
Из последующих вызовов функция require() использует объект экспорта из кеша вместо повторного выполнения модуля.
Следующий пример иллюстрирует, как это работает:
Сначала создайте новый модуль с именем dblogger.js со следующим кодом:
console.log('Connected to the DB');Затем используйте функцию require(), чтобы несколько раз включить модуль dblogger.js в app.js :
let dbLogger = require('./dblogger');
dbLogger = require('./dblogger');Выход:
DBLogger is loaded.
В этом примере вы можете увидеть сообщение 'DBLogger is loaded.' только один раз, а не два. Это означает, что Node.js оценивал dblogger.js только один раз.
Заключение
- В модулях CommonJS Node.js рассматривает файл JavaScript как модуль.
- Предоставьте доступ к переменным и функциям другому модулю, назначив их свойствам объекта
module.exports. - Node.js оборачивает код модуля в функцию-оболочку модуля перед его выполнением.
- Все переменные, константы, функции, классы и т. д., объявленные в модуле, относятся к модулю, а не к глобальной области.
- Node.js выполняет модуль только один раз и помещает результат в кеш для следующего использования.
