Зачем нужен index.js в Node.js проекте
Файл index.js в проектах Node.js
Файл index.js выполняет роль точки входа в приложение или модуль на Node.js. Когда в команде node index.js или в поле main файла package.json указывается директория, Node.js автоматически ищет в ней index.js. Этот файл отвечает за инициализацию, подключение зависимостей, запуск сервера или экспорт функций. Рассмотрим несколько способов его применения.
Основное использование: точка входа для сервера
Самый распространённый вариант - файл index.js содержит код запуска HTTP-сервера или Express-приложения.
// index.js (базовый HTTP-сервер)
const http = require('http');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Привет, мир!\n');
});
server.listen(port, hostname, () => {
console.log(`Сервер запущен на http://${hostname}:${port}/`);
});Node index js (файл index.js в node.js)
Запуск: node index.js. После запуска сервер слушает порт 3000. В package.json можно указать "main": "index.js" и использовать команду npm start через скрипт.
Типичные ошибки:
- Порт занят - возникает ошибка
EADDRINUSE. Решение: использовать свободный порт или завершить процесс. - Не указан main в package.json - при импорте через директорию (например,
require('./myapp')) Node.js не найдёт index.js. Решение: явно прописать "main": "index.js". - Синтаксическая ошибка - если используется ES-модули с расширением .mjs или в package.json поле "type": "module", то
requireне работает. Решение: заменить наimportили убрать тип модуля.
Как сделать единую точку доступа к модулям папки?
Вместо импорта каждого файла по отдельности можно использовать index.js для реэкспорта всех компонентов.
// utils/index.js
const { formatDate } = require('./date');
const { validateEmail } = require('./validation');
module.exports = { formatDate, validateEmail };// В другом файле
const { formatDate } = require('./utils'); // автомат. берёт index.jsПроблемы: циклические зависимости, когда moduleA требует moduleB, а moduleB снова требует moduleA через index.js. Решение: избегать таких циклов или переносить общие зависимости в отдельный модуль.
Как структурировать запуск Express-сервера с middleware?
index.js может содержать инициализацию Express, подключение middleware и маршрутов.
// index.js
const express = require('express');
const app = express();
app.use(express.json());
const userRoutes = require('./routes/users');
app.use('/api/users', userRoutes);
app.listen(3000, () => console.log('Сервер на порту 3000'));Ошибки: если middleware не подключены до маршрутов, тело запроса не парсится. Решение: порядок подключения - сначала middleware, потом маршруты. Также возможна ошибка EADDRINUSE при повторном запуске.
Как создать исполняемый CLI-скрипт через index.js?
Добавив шебанг #!/usr/bin/env node в начало, файл можно запускать как команду (после установки прав).
#!/usr/bin/env node
// index.js (CLI-скрипт)
const args = process.argv.slice(2);
if (args[0] === 'greet') {
console.log(`Привет, ${args[1] || 'мир'}!`);
} else {
console.log('Использование: node index.js greet [имя]');
}Проблемы: права на выполнение - нужно выполнить chmod +x index.js. Если после установки пакета глобально команда не найдена, проверьте поле "bin" в package.json.
Как упростить запуск вспомогательных скриптов (миграций, тестов)?
index.js может анализировать аргументы и выполнять разные функции.
// index.js
const args = process.argv.slice(2);
const command = args[0];
if (command === 'migrate') {
require('./scripts/migrate')();
} else if (command === 'seed') {
require('./scripts/seed')();
} else {
console.log('Доступные команды: migrate, seed');
}Запуск: node index.js migrate
Проблемы: при большом количестве команд файл становится громоздким. Решение: вынести логику в отдельные модули и использовать менеджер задач (например, commander или yargs).
Расширенные примеры использования index.js
Помимо базовых сценариев, index.js может применяться для сложной архитектуры. Каждый пример сопровождается кодом и результатом выполнения.
1. Кластеризация для многопроцессорной обработки
// index.js (кластер)
const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
console.log(`Главный процесс PID: ${process.pid}`);
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`Рабочий процесс ${worker.process.pid} завершён`);
});
} else {
http.createServer((req, res) => {
res.writeHead(200);
res.end('Hello from worker ' + process.pid);
}).listen(8000);
console.log(`Рабочий процесс ${process.pid} запущен`);
}Главный процесс PID: 12345 Рабочий процесс 12346 запущен Рабочий процесс 12347 запущен ... (по числу ядер)
Запуск: node index.js. Сервер использует все ядра CPU. Проблема: при обновлении кода нужно перезапускать все процессы. Решение: использовать менеджеры процессов (pm2).
2. Использование dotenv для конфигурации
// index.js с загрузкой переменных окружения
require('dotenv').config();
const express = require('express');
const app = express();
const PORT = process.env.PORT || 4000;
app.get('/', (req, res) => res.send('OK'));
app.listen(PORT, () => console.log(`Сервер на порту ${PORT}`));Файл .env в корне проекта:
PORT=5000Сервер на порту 5000
Важно: dotenv следует загружать в самом начале index.js, чтобы другие модули могли использовать переменные.
3. Одновременная поддержка CommonJS и ES-модулей
// index.js (CommonJS, но может импортировать ESM)
(async () => {
const { greeting } = await import('./greeting.mjs');
console.log(greeting('Мир'));
})();
// greeting.mjs (ES-модуль)
export function greeting(name) {
return `Привет, ${name}!`;
}Запуск: node index.js (при условии, что package.json не содержит "type": "module"). Результат: Привет, Мир!. Ошибка: динамический import возвращает Promise, поэтому нужна обёртка async. Без неё код выполнится до загрузки модуля.
4. Маршрутизация и обработка ошибок в Express
// index.js - структурированный сервер с middleware ошибок
const express = require('express');
const app = express();
app.use(express.json());
const routes = require('./routes');
app.use('/api', routes);
// middleware для обработки ошибок (после маршрутов)
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Внутренняя ошибка сервера' });
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`Сервер слушает порт ${PORT}`));// routes/index.js
const router = require('express').Router();
router.get('/hello', (req, res) => {
res.json({ message: 'Hello!' });
});
router.use((req, res) => res.status(404).json({ error: 'Не найдено' }));
module.exports = router;Результат при GET /api/hello: {"message":"Hello!"}. При GET /api/unknown: {"error":"Не найдено"}. Проблема: если middleware ошибок не последний, он может не сработать. Решение: располагать его после всех маршрутов.
5. index.js как task runner (миграции и сиды)
// index.js
const args = process.argv.slice(2);
const task = args[0];
switch (task) {
case 'migrate':
require('./tasks/migrate')().catch(err => console.error(err));
break;
case 'seed':
require('./tasks/seed')().catch(err => console.error(err));
break;
default:
console.log('Неизвестная задача. Используйте: migrate, seed');
}
// Пример tasks/migrate.js
module.exports = async function migrate() {
// Логика миграции
console.log('Миграция выполнена');
};Запуск: node index.js migrate → вывод: Миграция выполнена. Ошибки: если задача возвращает Promise без обработки, невыполненные обещания могут быть проигнорированы. Решение: всегда использовать .catch() или await в асинхронной функции.