Бортовой журнал
Бортовой журнал

Создать модуль в Node.js несложно — достаточно вынести часть кода в отдельный файл, экспортировать нужные функции или объекты и подключить их в другом месте через require. Подробнее — в этой статье.

Что такое Node.js и зачем нужны модули

Node.js — это среда выполнения JavaScript, которая создана на базе движка V8 от Google. Она позволяет запускать JavaScript не только в браузере, но и на сервере. Благодаря этому разработчики могут использовать один язык как для клиентской, так и для серверной части приложения.

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

Одни из ключевых элементов Node.js — это модули.

Модуль — это отдельный файл или блок кода, который выполняет определенную задачу: например, подключение к базе данных, работу с файлами, маршрутизацию запросов или шифрование данных. Они помогают разбивать проект на логические части, что делает код более понятным и удобным для поддержки.

С модулями разработчик может подключать только те компоненты, которые действительно нужны проекту.

Что такое require и module.exports

В Node.js каждая программа состоит из отдельных модулей, которые можно подключать и использовать в разных частях проекта. Для этого нужны два механизма — require и module.exports.

require — это функция, которая используется для подключения модулей. С ее помощью можно загрузить как встроенные модули Node.js (например, fs или http), так и собственные или внешние файлы. Например:

const fs = require('fs');
const myModule = require('./myModule');

В первом случае подключается встроенный модуль для работы с файловой системой, а во втором — пользовательский модуль из текущей директории.

module.exports, в свою очередь, определяет, какие данные или функции из файла будут доступны другим модулям после подключения через require. Это может быть отдельная функция, объект, класс или набор переменных. Например:

function sayHello(name) {
  console.log(`Привет, ${name}!`);
}

module.exports = sayHello;

Теперь этот модуль можно подключить в другом файле и использовать:

const greet = require('./sayHello');
greet('Андрей');

Таким образом, require и module.exports работают вместе: первый отвечает за импорт, а второй — за экспорт. Система модулей помогает структурировать проект, разделяя код на независимые части, которые легко поддерживать и переиспользовать.

Как создать собственный модуль

Чтобы добавить в проект собственный модуль, достаточно выделить часть логики в отдельный файл и правильно его оформить:

Откройте терминал и создайте папку для будущего модуля. Перейдите в нее:

mkdir math-utils
cd math-utils

Чтобы использовать модуль в других проектах или подключать внешние пакеты, выполните:

npm init -y

После этого появится файл package.json с основной информацией о модуле. Откройте редактор и создайте файл index.js:

nano index.js

Внутри index.js реализуйте нужные функции. Например, создайте модуль с математическими операциями: вычисление факториала, суммы массива и проверка числа на простоту:

// Функция для вычисления факториала
function factorial(n) {
  if (n < 0) return undefined;
  if (n === 0) return 1;
  return n * factorial(n - 1);
}

// Функция для вычисления суммы элементов массива
function sumArray(arr) {
  return arr.reduce((acc, val) => acc + val, 0);
}

// Функция для проверки, является ли число простым
function isPrime(num) {
  if (num <= 1) return false;
  for (let i = 2; i <= Math.sqrt(num); i++) {
    if (num % i === 0) return false;
  }
  return true;
}

Чтобы эти функции были доступны другим файлам, их нужно экспортировать:

exports.factorial = factorial;
exports.sumArray = sumArray;
exports.isPrime = isPrime;

Теперь другие части вашего проекта смогут импортировать и использовать эти функции. Чтобы протестировать их, создайте файл test.js:

nano test.js

В нем подключите ваш модуль и вызовите функции:

const math = require('./index');

console.log('Факториал 5:', math.factorial(5)); // 120
console.log('Сумма массива [1, 2, 3]:', math.sumArray([1, 2, 3])); // 6
console.log('Число 7 простое?', math.isPrime(7)); // true
console.log('Число 12 простое?', math.isPrime(12)); // false

Запустите тестовый файл в терминале:

node test.js

В консоли вы увидите результаты выполнения всех функций.

Работа с локальными модулями

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

Локальные модули — это ваш собственный код, который вы структурируете по отдельным файлам и папкам. Например, если вы реализуете обработку входящих запросов, работу с базой данных или просто несколько вспомогательных функций, все это можно вынести в отдельные файлы.

Каждый локальный модуль представляет собой отдельный файл или набор файлов, в которых реализована определенная часть функциональности — например, работа с базой данных, валидация данных, вспомогательные функции для форматирования текста или обработки ошибок.

Как создать и подключить локальный модуль

Подключение локального модуля начинается с создания нового файла. Например, пусть у вас есть файл math.js с простыми функциями для вычислений:

function add(a, b) {
  return a + b;
}

function multiply(a, b) {
  return a * b;
}

module.exports = { add, multiply };

Чтобы воспользоваться этими функциями в другом файле — например, в основном файле приложения app.js, — подключите модуль через require с обязательным относительным путем:

const math = require('./math');

console.log(math.add(2, 3)); // 5
console.log(math.multiply(4, 5)); // 20

Node.js загрузит модуль из файла, который находится рядом с app.js. Если файл лежит в подпапке, путь будет выглядеть так: require('./utils/math').

Как структурировать локальные модули

Когда проект на Node.js начинает разрастаться, поддерживать порядок в коде становится все важнее. Грамотная структура локальных модулей помогает не только быстро находить нужные файлы, но и облегчает командную работу и дальнейшее развитие приложения.

Как правило, модули группируют по смысловым блокам — например, выносит все, что связано с пользователями, в папку users, а работу с заказами — в orders. Это позволяет сразу понять, за что отвечает тот или иной файл.

Часто внутри крупных папок создают дополнительные подпапки: например, для разных типов логики — контроллеры, сервисы, модели.

Как может выглядеть структура типового проекта:

my-app/
├── app.js
├── users/
│   ├── createUser.js
│   ├── getUser.js
│   └── userModel.js
├── orders/
│   ├── createOrder.js
│   ├── getOrder.js
│   └── orderModel.js
├── utils/
│   ├── logger.js
│   └── formatDate.js
└── config/
    └── index.js

Если внутри папки есть файл index.js, можно использовать его для объединения и экспорта нескольких функций или классов из других файлов этой папки. Тогда в коде достаточно будет одного подключения к папке, без указания файла:

// users/index.js
const createUser = require('./createUser');
const getUser = require('./getUser');
const userModel = require('./userModel');

module.exports = {
  createUser,
  getUser,
  userModel
};

И в основном файле:

const users = require('./users');
users.createUser(...);

Подобная организация модулей облегчает масштабирование проекта. Когда появляется новая задача, вы просто добавляете нужный файл в подходящую папку — и структура приложения остается логичной.

Как импортировать локальные модули

Чтобы подключить локальный модуль, всегда используйте функцию require с относительным путем — он начинается с ./, если модуль находится в той же папке, или с ../, если он расположен на уровень выше. Например, если у вас есть файл helpers.js в той же директории, импорт будет выглядеть так:

const helpers = require('./helpers');

Если же модуль лежит в подпапке, путь указывается относительно текущего файла:

const validator = require('./utils/validator');

Важно понимать: если вы не укажете относительный путь и напишете просто require('validator'), Node.js будет искать модуль среди установленных внешних пакетов, а не в вашем проекте. Это частая причина ошибок, особенно если название вашего файла совпадает с каким-либо npm-пакетом.

Импортировать можно не только целый модуль, но и отдельные функции, классы или объекты, если они экспортированы как свойства объекта. Например, если модуль экспортирует сразу несколько сущностей:

// math.js
function add(a, b) { return a + b; }
function subtract(a, b) { return a - b; }

module.exports = { add, subtract };

То при импорте можно воспользоваться деструктуризацией:

const { add, subtract } = require('./math');

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

Также, если ваша папка-модуль содержит файл index.js, его можно импортировать просто по названию папки, без указания самого файла:

const db = require('./db'); // автоматически подключит ./db/index.js

Импортировать локальные модули можно в любом месте проекта и в любом количестве файлов — главное, чтобы путь был указан правильно.

Как экспортировать локальные модули

Экспорт в Node.js позволяет сделать функции, классы, объекты или данные, описанные в одном файле, доступными в других частях приложения. За это отвечает специальный объект module.exports, а также сокращенная форма — exports.

Самый простой способ — экспортировать одну функцию или класс напрямую:

// greeting.js
function sayHello(name) {
  return `Привет, ${name}!`;
}

module.exports = sayHello;

Теперь этот модуль можно импортировать в другом файле и сразу использовать функцию sayHello. Но зачастую нужно экспортировать не одну функцию, а сразу несколько сущностей. В таком случае формируют объект и экспортируют его целиком:

// math.js
function add(a, b) {
  return a + b;
}

function multiply(a, b) {
  return a * b;
}

module.exports = {
  add,
  multiply
};

Теперь при импорте в другом файле все функции будут доступны через объект:

const math = require('./math');

console.log(math.add(2, 3)); // 5
console.log(math.multiply(4, 5)); // 20

Если модуль достаточно большой, в разных его частях можно добавлять функции к объекту exports по отдельности:

// helpers.js
exports.formatDate = function(date) {
  // реализация форматирования
};

exports.capitalize = function(str) {
  // реализация преобразования регистра
};

Работа с внешними модулями

Внешние модули — это готовые решения, которые устанавливаются через npm. Обычно это известные библиотеки, уже зарекомендовавшие себя в сообществе: те же express для серверов, mongoose для работы с MongoDB, dotenv для работы с переменными окружения.

Как установить внешний модуль

Допустим, вам понадобилась библиотека для работы с запросами к API, например, популярный модуль axios. Чтобы добавить его в свой проект, выполните в терминале команду:

npm install axios

После этого в каталоге вашего проекта появится папка node_modules, если ее еще не было, а также файл package-lock.json (он нужен для фиксации версий зависимостей). В файле package.json автоматически появится новая запись в разделе dependencies:

"dependencies": {
  "axios": "^1.6.0"
}

Это означает, что теперь модуль axios официально закреплен за вашим проектом, и любой другой разработчик или вы сами сможете в будущем просто выполнить npm install, чтобы подтянуть все нужные внешние библиотеки, не устанавливая их вручную.

Также, если вы хотите установить модуль только для разработки (например, утилиту для тестирования), используйте флаг --save-dev:

npm install jest --save-dev

В таком случае зависимость попадет в раздел devDependencies в package.json.

Если необходимо установить сразу несколько модулей, их имена можно перечислить через пробел:

npm install express mongoose cors

Node.js сам скачает их из реестра npm и добавит в проект.

Как импортировать и использовать внешний модуль

Чтобы начать использовать установленный модуль, достаточно подключить его в нужном файле с помощью функции require. Главное отличие от локальных модулей — здесь не нужен относительный путь. Просто укажите имя установленного пакета.

Например, если вы установили модуль axios для отправки HTTP-запросов, импортировать его можно так:

const axios = require('axios');

Теперь весь функционал библиотеки доступен через переменную axios. Можно сразу использовать методы этого модуля, например, отправить GET-запрос:

axios.get('https://api.github.com/users/octocat')
  .then(response => {
    console.log('Данные пользователя:', response.data);
  })
  .catch(error => {
    console.error('Ошибка запроса:', error);
  });

Импортировать внешний модуль можно в любом файле проекта, где он необходим. Например, если для форматирования дат используется библиотека moment, просто подключите ее так:

const moment = require('moment');

console.log('Текущая дата и время:', moment().format('YYYY-MM-DD HH:mm:ss'));

Некоторые модули предоставляют не только один объект, но и набор функций. В таком случае можно применять деструктуризацию при импорте:

const { shuffle, uniq } = require('lodash');

const arr = [1, 2, 2, 3, 4];
console.log('Перемешанный массив:', shuffle(arr));
console.log('Уникальные значения:', uniq(arr));

Node.js найдет и подключит внешний модуль из папки node_modules, и вы сможете пользоваться всеми возможностями библиотеки так же, как если бы это была часть вашего собственного кода.

Как управлять версиями внешних модулей

Когда вы устанавливаете внешний модуль через npm, по умолчанию ставится самая свежая версия. Если вы хотите установить определенную версию, укажите ее через символ @ после имени пакета. Например, чтобы установить именно версию 4.18.2 пакета express, используйте команду:

npm install express@4.18.2

Можно также устанавливать только мажорную или минорную версию с помощью символов:

  • ^ — разрешает обновления только внутри основной версии (например, ^1.2.3 позволит обновлять до 1.x.x, но не до 2.0.0).
  • ~ — разрешает обновления только внутри текущей минорной версии (например, ~1.2.3 — до 1.2.x).

Чтобы обновить все зависимости согласно ограничениям из package.json, выполните:

npm update

Если нужно обновить конкретный модуль до самой последней версии, используйте:

npm install <имя_пакета>@latest

Если какой-то пакет больше не используется, его стоит удалить командой:

npm uninstall <имя_пакета>

Пример — создаем модуль конфигурации

Чтобы приложение оставалось удобным в поддержке, важно не размазывать настройки по разным файлам, а собрать их в одном месте. Параметры вроде адреса базы данных, порта сервера или секретных ключей часто меняются — и гораздо проще, когда все это хранится централизованно. Для этого создадим модуль конфигурации.

Начнем с нового файла config.js в корне проекта. В нем соберем все ключевые настройки и сгруппируем их по смыслу. Например, отдельно запишем параметры для базы данных, сервера и авторизации:

// config.js
const config = {
  db: {
    host: 'localhost', // адрес базы данных
    port: 27017, // порт подключения
    name: 'myapp' // имя базы данных
  },
  server: {
    port: 3000 // порт, на котором работает сервер
  },
  jwtSecret: 'mySuperSecretKey' // секретный ключ для токенов
};

module.exports = config;

Мы используем объект config, чтобы сгруппировать значения по логическим разделам. Благодаря этому структура остается понятной, и нужные параметры легко найти. Если потребуется изменить порт или имя базы, достаточно исправить одну строку — и обновление автоматически применится во всем проекте.

Теперь подключим конфигурацию в основном файле приложения:

// app.js
const config = require('./config');

console.log(`Сервер запустится на порту ${config.server.port}`);

Точно так же можно использовать эти настройки при подключении базы данных или других сервисов:

const config = require('./config');

// Пример подключения к базе:
// mongoose.connect(`mongodb://${config.db.host}:${config.db.port}/${config.db.name}`);

Если позже появится новая настройка, например, API-ключ или путь к папке с логами, просто добавим ее в объект config. Все модули, которые используют конфигурацию, сразу получат доступ к новому параметру — без дополнительных правок.

Развертывание модуля: как опубликовать и протестировать

Разработанный модуль можно не только использовать внутри своего проекта, но и опубликовать, чтобы другие разработчики могли установить его через npm.

Начнем с тестирования. Самый простой способ проверить модуль — воспользоваться интерактивной средой Node.js под названием REPL (Read–Eval–Print Loop). Она позволяет вводить команды построчно и сразу видеть результат выполнения.

Запустить REPL можно прямо из терминала командой:

node

После запуска вы попадете в интерактивный режим. Подключите к нему модуль, который хотим проверить. Если вы находитесь в папке с модулем, выполните:

const config = require('./index');

Теперь можно вызывать его методы или обращаться к свойствам объекта конфигурации:

config.server.port;

Если модуль возвращает нужные значения — значит, экспорт работает корректно.

Выйти из REPL можно командой:

.exit

Чтобы протестировать модуль в реальных условиях, создадим чистую папку и установим туда нашу библиотеку как внешнюю зависимость:

mkdir test-config
cd test-config
npm init -y
npm install ../путь_к_вашему_модулю

Создадим файл index.js и подключим модуль так, как это сделал бы пользователь из npm:

const config = require('my-config-module');

console.log(`Подключение к базе: ${config.db.host}:${config.db.port}`);

Если код выполняется без ошибок и выводит ожидаемые данные, значит, все работает как нужно — модуль можно публиковать.

Перед публикацией проверьте package.json: убедитесь, что в нем заполнены основные поля — имя, версия, описание, точка входа (main) и лицензия. Например:

{
  "name": "my-config-module",
  "version": "1.0.0",
  "description": "Модуль конфигурации для Node.js",
  "main": "index.js",
  "license": "MIT"
}

Теперь можно переходить к публикации.

Чтобы выложить модуль в npm, авторизуйтесь в своем npm-аккаунте:

npm login

Проверьте, что пакет готов к публикации и содержит только нужные файлы:

npm pack

Эта команда создаст архив, который можно просмотреть, чтобы убедиться, что туда не попали временные или конфиденциальные данные.

Опубликуйте модуль:

npm publish

Проверьте, что публикация прошла успешно, установив модуль в новую папку:

mkdir verify
cd verify
npm init -y
npm install my-config-module

Теперь ваш модуль доступен в реестре npm и может быть установлен в любой проект командой:

npm install my-config-module

Если позже вы обновите код, просто измените версию в package.json (например, с 1.0.0 на 1.0.1) и выполните публикацию снова:

npm publish

Финальные рекомендации

Работа с модулями в Node.js становится проще, если с самого начала придерживаться нескольких практических правил. Они помогут поддерживать проект в порядке, избежать дублирования кода и сделать модуль удобным для повторного использования.

  • Продумывайте структуру заранее. Разделяйте код по смыслу: отдельные функции, работа с данными, взаимодействие с API — все это лучше выносить в собственные модули. Так искать нужный файл станет проще.
  • Не экспортируйте лишнего. Оставляйте только те функции и объекты, которые действительно должны использоваться другими частями приложения.
  • Следите за версиями. При обновлениях модуля всегда меняйте номер версии в package.json и используйте семантическое версионирование (1.0.1, 1.1.0, 2.0.0). Это помогает понять, есть ли изменения в функциональности или обратной совместимости.
  • Добавляйте документацию. Даже небольшой модуль стоит снабдить простым описанием в README.md. Пример использования, список функций и короткое объяснение — этого достаточно, чтобы через время быстро вспомнить, как все устроено.
  • Тестируйте в отдельной среде. Перед публикацией проверьте работу модуля за пределами вашего проекта. Можно создать отдельную папку и установить туда модуль локально через npm install ../путь_к_модулю, чтобы убедиться, что все подключается и работает корректно.
  • Размещайте проект на сервере. Если хочется протестировать или запустить модуль в условиях, приближенных к реальной работе, удобно использовать VPS-сервер. Например, в SpaceWeb можно быстро развернуть сервер с Node.js, установить зависимости и проверить, как модуль ведет себя в боевой среде.

И наконец: не бойтесь экспериментировать! Попробуйте вынести небольшую часть логики в модуль, подключите ее в другом файле и посмотрите, как это упростит ваш код.

Блок FAQ

Как создать модуль в NodeJS?

Создать модуль в Node.js можно в несколько шагов:

  • Создайте файл, например math.js.
  • Определите функции или классы, которые будут в модуле:

function add(a, b) {
  return a + b;
}

  • Экспортируйте их с помощью module.exports:

module.exports = { add };

  • Подключите модуль в другом файле через require:

const math = require('./math');
console.log(math.add(2, 3));

Что такое node_modules?

node_modules — это папка, в которой Node.js хранит все установленные зависимости проекта. Когда вы выполняете команду npm install, пакетный менеджер npm скачивает нужные библиотеки и помещает их именно туда.

В этой папке находятся все внешние модули, от которых зависит ваш проект, а также их собственные зависимости.

Как называется стандартный инструмент Node.js для управления пакетами и модулями?

Стандартный инструмент Node.js для управления пакетами и модулями называется npm (Node Package Manager).

Он используется для установки, обновления, удаления и публикации пакетов, а также для управления зависимостями проекта через файл package.json.

Что такое module exports?

module.exports — это объект, с помощью которого в Node.js указывают, какие части кода из модуля будут доступны снаружи. Проще говоря, все, что вы присваиваете module.exports, можно использовать в другом файле.

Как опубликовать модуль в NPM?

  • Подготовьте проект. Убедитесь, что в корне есть файл package.json с заполненными полями name, version, description, main и license.
  • Войдите в свой npm-аккаунт:

npm login

  • Проверьте, что в пакет попадут только нужные файлы:

npm pack

  • Опубликуйте модуль:

npm publish

Как управлять зависимостями в модуле Node.js?

Зависимостями в модуле Node.js управляют через файл package.json. В нем хранятся все пакеты, установленные через npm. Чтобы добавить зависимость, используют команду npm install имя_пакета, удалить — npm uninstall имя_пакета, обновить — npm update. При переносе проекта достаточно выполнить npm install, чтобы восстановить все зависимости.