Node.js предоставляет нативный модуль fs
для отслеживания изменений файлов. Вот базовая реализация:
const fs = require('fs');
const { spawn } = require('child_process');
let appProcess = startProcess();
function startProcess() {
const child = spawn('node', ['app.js'], { stdio: 'inherit' });
child.on('exit', (code) => {
if (code === 100) { // Код 100 для перезагрузки
console.log('Restarting process...');
appProcess = startProcess();
}
});
return child;
}
fs.watch('app.js', (eventType) => {
if (eventType === 'change') {
console.log('File changed, restarting...');
appProcess.kill();
}
});
Для реальных проектов нужно отслеживать всю директорию и вложенные файлы:
const path = require('path');
const fs = require('fs');
function watchDirectory(dir, callback) {
fs.watch(dir, { recursive: true }, (event, filename) => {
if (filename && !filename.includes('node_modules')) {
const ext = path.extname(filename);
if (['.js', '.json', '.mjs'].includes(ext)) {
callback();
}
}
});
}
Важно правильно очищать кэш модулей при перезагрузке:
function restartApp() {
// Очищаем кэш всех файлов кроме node_modules
Object.keys(require.cache).forEach((modulePath) => {
if (!modulePath.includes('node_modules')) {
delete require.cache[modulePath];
}
});
// Перезапускаем основной модуль
require('./app');
}
Добавим debounce чтобы избежать множественных перезагрузок:
const debounce = (fn, delay) => {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), delay);
};
};
const restart = debounce(() => {
console.log('Restarting server...');
process.send({ type: 'RESTART' });
}, 300);
watchDirectory('.', restart);
Более продвинутый вариант с кластером:
const cluster = require('cluster');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
// Запускаем workers
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
// Отслеживаем изменения файлов
fs.watch('.', { recursive: true }, (event, filename) => {
if (filename.endsWith('.js')) {
Object.values(cluster.workers).forEach((worker) => {
worker.send('restart');
});
}
});
} else {
require('./app');
process.on('message', (msg) => {
if (msg === 'restart') {
process.exit(100); // Специальный код для перезагрузки
}
});
}
Хотя вопрос про нативные средства, стоит упомянуть популярные решения:
Node.js предоставляет все необходимые инструменты (fs.watch
, child_process
, cluster
) для реализации автоматической перезагрузки. Ключевые аспекты - правильное отслеживание файлов, очистка кэша модулей и грамотная обработка перезапуска. Для production-решений лучше использовать специализированные инструменты, но понимание нативной реализации важно для глубокого понимания работы Node.js.