Как автоматически перезагрузить файлы в Node.js?

444

Любые идеи о том, как я могу реализовать автоматическую перезагрузку файлов в Node.js? Я устал от перезапуска сервера каждый раз, когда я меняю файл. Судя по всему, require()функция Node.js не перезагружает файлы, если они уже были необходимы, поэтому мне нужно сделать что-то вроде этого:

var sys     = require('sys'), 
    http    = require('http'),
    posix   = require('posix'),
    json    = require('./json');

var script_name = '/some/path/to/app.js';
this.app = require('./app').app;

process.watchFile(script_name, function(curr, prev){
    posix.cat(script_name).addCallback(function(content){
        process.compile( content, script_name );
    });
});

http.createServer(this.app).listen( 8080 );

И в файле app.js у меня есть:

var file = require('./file');
this.app = function(req, res) { 
    file.serveFile( req, res, 'file.js');  
}

Но это также не работает - я получаю сообщение об ошибке, в process.compile()котором говорится, что «require» не определено. process.compileоценивает app.js , но не имеет ни малейшего представления о глобалах node.js.

disc0dancer
источник
4
Вы знаете, что вы можете просто запустить этот код при каждом запросе:Object.keys(require.cache).forEach(function(key) { delete require.cache[key]; });
Башня
1
См. Strongloop.com/strongblog/…
Моала

Ответы:

564

Хороший, вплоть до настоящего времени альтернативы supervisorявляется nodemon:

Отслеживайте любые изменения в вашем приложении node.js и автоматически перезагружайте сервер - идеально подходит для разработки

Использовать nodemon:

$ npm install nodemon -g
$ nodemon app.js
Мариус Бутук
источник
2
и если вы хотите использовать его в Nitrous.io - $ nodemon -L yourfile.js(полное объяснение на coderwall.com/p/aqxl_q )
drzaus
3
Но в этом случае он также перезапускает процесс сервера.
Филипе
@ Филипе, ты прав. Я перенаправлен, чтобы войти снова. Я бы хотел, чтобы он загружал только этот конкретный модифицированный модуль.
ar2015
8
automatically restart the server - perfect for developmentэто слишком много гиперболы. Перезагрузка сервера может означать вход в бэкэнд-сервисы, что в моем случае занимает много времени. «Идеально для разработки» - это что-то вроде горячих перезагрузок классов, когда процесс работает в памяти, не теряя состояния а-ля, что делает студия android при изменении исходного кода.
nurettin
2
используйте npm install [--save-dev | -D] nodemonдля ограничения установки до объема проекта.
themefield
312

нод-супервайзер - это круто

использование для перезагрузки при сохранении:

npm установить супервизор -g
supervisor app.js

от Исаака - http://github.com/isaacs/node-supervisor

Ануп Бишной
источник
3
npm установить -g супервизор. Это должно быть установлено глобально.
Камаль Редди
На OSx 10.2.8 мне пришлось запустить его с помощью sudo
Timopheym
2
Пришлось так запустить под Windows:"C:\Program Files\nodejs\node.exe" C:\Users\Mark\AppData\Roaming\npm\node_modules\supervisor\lib\cli-wrapper.js app.js
mpen
1
без -g или Судо в приложение корня: npm install supervisor, node node_modules/supervisor/lib/cli-wrapper.js app.js( у меня есть , не корневой установки узла)
ч-Киппо
1
@Mark Это означает, что узел не в вашемPATH
Блейз
88

я нашел простой способ:

delete require.cache['/home/shimin/test2.js']
Inshua
источник
7
Это замечательно, если вы хотите перезагрузить внешние библиотеки без перезапуска приложения - в моем случае, IRC-бот.
Мишель Тилли
Это отлично! Так просто и так хорошо работает. Всякий раз, когда приходит запрос, я просто кэширую кучу файлов, которые не хранят состояние.
Воган
16
delete require.cache[require.resolve('./mymodule.js')]; решить дело с реальными путями
Эдуардо
Это безопасно делать или считается "плохой практикой" или "только развитием"?
jocull
2
@jocull Я не думаю, что это безопасно, так как он может воссоздать классы и функции или любой другой экспорт, что приводит к различным ссылкам при сравнении с===
Kroltan
20

Если кто-то все еще приходит к этому вопросу и хочет решить его, используя только стандартные модули, я сделал простой пример:

var process = require('process');
var cp = require('child_process');
var fs = require('fs');

var server = cp.fork('server.js');
console.log('Server started');

fs.watchFile('server.js', function (event, filename) {
    server.kill();
    console.log('Server stopped');
    server = cp.fork('server.js');
    console.log('Server started');
});

process.on('SIGINT', function () {
    server.kill();
    fs.unwatchFile('server.js');
    process.exit();
});

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

fs.watch('./', function (event, filename) { // sub directory changes are not seen
    console.log(`restart server`);
    server.kill();
    server = cp.fork('server.js');    
})

Этот код был создан для API Node.js 0.8, он не адаптирован для некоторых конкретных нужд, но будет работать в некоторых простых приложениях.

ОБНОВЛЕНИЕ: Этот функционал реализован в моем модуле simpleR , GitHub repo

micnic
источник
1
Это отличное и простое решение. Я просто использовал его для бота, который должен был обновляться из git, когда об этом сказал модератор. Проблема заключалась в том, что, как только вы оказались внутри приложения, вы не можете перезапустить себя. Однако я могу использовать ваш метод для создания экземпляра бота и просмотра дотфайла. Затем бот обновляется, касается файла точек и автоматически запускается программой запуска. Потрясающие!
Фред
@ Фред, я рад это слышать :) Я реализую это решение в модуле, скоро, я думаю, у меня есть еще несколько идей, как расширить его функциональность
micnic
Если файл watchне нужен, перезагрузка может быть выполнена без fsпрослушивания другого сигнала.
Владимир Вуканац
18

Nodemon появился первым в поиске Google, и, похоже, он добился цели :

npm install nodemon -g
cd whatever_dir_holds_my_app
nodemon app.js
JnBrymn
источник
8

Существует Node-Supervisor, который вы можете установить

npm install supervisor

см. http://github.com/isaacs/node-supervisor

Ричард Метцлер
источник
2
Это больше о перезапуске сервера в случае сбоя. Узел-супервизор также перезапускает весь процесс, когда наблюдаемые файлы были изменены. Это не горячая перезагрузка в строгом смысле.
Вскоре
Хотя это и не горячая загрузка, этот инструмент действительно полезен, если вы просто хотите, чтобы код автоматически перезагружался во время разработки, чтобы вам не приходилось перезапускать узел в командной строке после каждого изменения.
Дерек Дамер
7

Изменить: мой ответ устарел. Node.js - очень быстро меняющаяся технология.

Я также задавался вопросом о перезагрузке модулей. Я изменил node.js и опубликовал исходный код на Github в nalply / node . Единственная разница заключается в функции require. У него есть необязательный второй аргумент reload.

require(url, reload)

Для перезагрузки app.jsв текущем каталоге используйте

app = require("./app", true);

Напишите что-то вроде этого, и у вас есть автоматическая перезагрузка:

process.watchFile(script_name, function(curr, prev) {
    module = reload(script_name, true);
});

Единственная проблема, которую я вижу, - это переменная module, но я сейчас над ней работаю.

nalply
источник
7

nodemonотличный Я просто добавляю больше параметров для отладки и просмотра параметров.

package.json

  "scripts": {
    "dev": "cross-env NODE_ENV=development nodemon --watch server --inspect ./server/server.js"
  }

Команда: nodemon --watch server --inspect ./server/server.js

В то время как:

--watch serverПерезапустите приложение при изменении .js, .mjs, .coffee, .litcoffee, и .jsonфайлы в serverпапке (включены вложенные папки).

--inspect Включить удаленную отладку.

./server/server.js Точка входа.

Затем добавьте следующую конфигурацию в launch.json(VS Code) и начните отладку в любое время.

{
    "type": "node",
    "request": "attach",
    "name": "Attach",
    "protocol": "inspector",
    "port": 9229
}

Обратите внимание, что лучше установить nodemonкак dev-зависимость проекта. Таким образом, членам вашей команды не нужно устанавливать его или запоминать аргументы команды, они просто npm run devначинают хакерство.

Смотрите больше на nodemonдокументах: https://github.com/remy/nodemon#monitoring-multiple-directories

Нин Фам
источник
Глобирование не поддерживается в последних версиях nodemon (по крайней мере, 1.19.0). Просто используйте вместо этого nodemon --watch server --inspect ./server/server.js.
Алекс
Спасибо @Alex за вашу информацию. Обновил ответ.
Фам
5

В списке рассылки node.js недавно появилась тема на эту тему. Краткий ответ - нет, в настоящее время невозможно автоматически перезагрузить требуемые файлы, но несколько человек разработали патчи, которые добавляют эту функцию.

Хави
источник
1
+1 да Я участвовал в обсуждении. Я признал, что мое решение слишком простое. Работает только в том случае, если самому горячему модулю не требуются дополнительные модули. Решение Felix более продуманно, но обсуждается, действительно ли автоматическая перезагрузка принадлежит ядру.
Вскоре
5

еще одно решение этой проблемы использует навсегда

Еще одна полезная возможность Forever заключается в том, что он может при желании перезапустить ваше приложение, если какие-либо исходные файлы были изменены. Это освобождает вас от необходимости вручную перезагружать каждый раз, когда вы добавляете функцию или исправляете ошибку. Чтобы запустить Forever в этом режиме, используйте флаг -w:

forever -w start server.js
Теоман Шипахи
источник
Странно, но с флагом -w мое приложение express.js не использует CSS.
Коста
5

node-dev прекрасно работает. НПМinstall node-dev

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

запустите ваше приложение из командной строки с помощью:

node-dev app.js

l3o
источник
3

Вот сообщение в блоге о Hot Reloading для Node. Он предоставляет ветку github Node, которую вы можете использовать для замены вашей установки Node, чтобы включить горячую перезагрузку.

Из блога:

var requestHandler = require('./myRequestHandler');

process.watchFile('./myRequestHandler', function () {
  module.unCacheModule('./myRequestHandler');
  requestHandler = require('./myRequestHandler');
}

var reqHandlerClosure = function (req, res) {
  requestHandler.handle(req, res);
}

http.createServer(reqHandlerClosure).listen(8000);

Теперь, каждый раз, когда вы изменяете myRequestHandler.js, приведенный выше код заметит и заменит локальный requestHandler новым кодом. Любые существующие запросы будут продолжать использовать старый код, в то время как любые новые входящие запросы будут использовать новый код. И все это без остановки сервера, отказов от любых запросов, преждевременного уничтожения любых запросов или даже от умного балансировщика нагрузки.

Четан
источник
Единственное, что есть в этом решении, это то, что он является форком старой версии Node, поэтому перед использованием его придется настроить и объединить с последней версией (если вы не возражаете против использования более старой версии Node).
Четан
3

Я работаю над созданием довольно маленькой "вещи" для узлов, которая может загружать / выгружать модули по своему усмотрению (то есть, вы можете перезапустить часть своего приложения без остановки всего приложения). Я включил (очень глупое) управление зависимостями, так что если вы хотите остановить модуль, все модули, которые зависят от этого, также будут остановлены.

Пока все хорошо, но потом я наткнулся на вопрос о том, как перезагрузить модуль. По-видимому, можно просто удалить модуль из кэша «require» и выполнить работу. Так как я не стремлюсь напрямую изменять исходный код узла, я придумал очень хакерский взлом, который заключается в следующем: поиск в стеке отслеживает последний вызов функции «require», захватывает ссылку на ее поле «cache» и ... ну, удалите ссылку на узел:

    var args = arguments
    while(!args['1'] || !args['1'].cache) {
        args = args.callee.caller.arguments
    }
    var cache = args['1'].cache
    util.log('remove cache ' + moduleFullpathAndExt)
    delete( cache[ moduleFullpathAndExt ] )

Еще проще, на самом деле:

var deleteCache = function(moduleFullpathAndExt) {
  delete( require.cache[ moduleFullpathAndExt ] )
}

Видимо, это работает просто отлично. Я понятия не имею, что означают эти аргументы ["1"], но он делает свою работу. Я полагаю, что ребята из узла когда-нибудь реализуют средство перезагрузки, поэтому я думаю, что пока это решение тоже приемлемо. (кстати, моя «вещь» будет здесь: https://github.com/cheng81/wirez , зайдите туда через пару недель, и вы должны увидеть, о чем я говорю)

cheng81
источник
.. конечно не все так просто. Это работает, только если в стеке вызовов есть запрос require. Да ладно, легкий взлом на вершине взлома: напиши это во временном скрипте и требуй его во время выполнения. Сделал это, это работает .., и это даже очищает себя от кэша
cheng81
И на самом деле это было проще: удалить (require.cache [moduleFullpathAndExt])
cheng81
Модули Node.js фактически обернуты в анонимную функцию, которая и используется для инкапсуляции модуля. Каждый модуль на самом деле выглядит так function (module, require) { /* your code */ }. Когда вы принимаете это во внимание, arguments[1]указывает на require. И цикл while предназначен для ситуаций, когда вы вызываете это из другой функции в модуле (он просто поднимается по иерархии функций и проверяет значения аргументов, передаваемые каждому).
JK
3

Вы можете использовать nodemon из NPM . И если вы используете генератор Express, то вы можете использовать эту команду в папке вашего проекта:

nodemon npm start

или используя режим отладки

DEBUG=yourapp:* nodemon npm start

Вы также можете запустить напрямую

nodemon your-app-file.js

Надеюсь, это поможет.

azwar_akbar
источник
1

решение по адресу: http://github.com/shimondoodkin/node-hot-reload

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

это означает, что если вы сделали: var x = require ('foo'); у = х; г = x.bar; и горячо перезагрузил его.

это означает, что вы должны заменить ссылки, хранящиеся в x, y и z. в горячей функции обратного вызова reaload.

некоторые люди путают горячую перезагрузку с автоматическим перезапуском. Мой модуль nodejs-autorestart также имеет встроенную поддержку для автоматического запуска при загрузке. если у вас небольшое приложение, автоматический перезапуск - это хорошо, но когда у вас большое приложение, горячая перезагрузка более подходит. просто потому, что горячая перезагрузка быстрее.

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

Шимон Дудкин
источник
1

Не обязательно использовать nodemon или другие подобные инструменты. Просто используйте возможности вашей IDE.

Вероятно, лучшим из них является IntelliJ WebStorm с функцией горячей перезагрузки (автоматическая перезагрузка сервера и браузера) для Node.js .

lukyer
источник
1

Вот низкотехнологичный метод для использования в Windows. Поместите это в пакетный файл с именем serve.bat:

@echo off

:serve
start /wait node.exe %*
goto :serve

Теперь вместо запуска node app.jsиз командной оболочки cmd запуститеserve app.js .

Это откроет новое окно оболочки с запущенным сервером. Пакетный файл будет заблокирован (из-за/wait ) до тех пор, пока вы не закроете окно оболочки, после чего исходная командная оболочка cmd спросит: «Завершить пакетное задание (Y / N)?» Если вы ответите «N», то сервер будет перезапущен.

Каждый раз, когда вы хотите перезапустить сервер, закройте окно сервера и ответьте «N» в командной консоли.

Йоу йоу
источник
1

структура моего приложения:

NodeAPP (folder)
   |-- app (folder)
      |-- all other file is here
   |-- node_modules (folder)
   |-- package.json
   |-- server.js (my server file)

сначала установите reload с помощью этой команды:

npm install [-g] [--save-dev] reload

затем измените package.json :

"scripts": {
    "start": "nodemon -e css,ejs,js,json --watch app"
}

теперь вы должны использовать reload в файле вашего сервера :

var express = require('express');
var reload = require('reload');
var app = express();

app.set('port', process.env.PORT || 3000);

var server = app.listen(app.get('port'), function() {
    console.log( 'server is running on port ' + app.get('port'));
});

reload(server, app);

и для последнего изменения, в конце вашего ответа отправьте этот скрипт :

<script src="/reload/reload.js"></script>

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

npm start
کسری کرمی
источник
Этот подход не работает, однако, те, что приведены в npmjs.com/package/reload (для приложений Express), делают.
Макси Беркманн
0

Использовать этот:

function reload_config(file) {
  if (!(this instanceof reload_config))
    return new reload_config(file);
  var self = this;

  self.path = path.resolve(file);

  fs.watchFile(file, function(curr, prev) {
    delete require.cache[self.path];
    _.extend(self, require(file));
  });

  _.extend(self, require(file));
}

Все, что вам нужно сделать сейчас, это:

var config = reload_config("./config");

И конфиг будет автоматически перезагружен :)

offlinehacker
источник
Есть версия, которая не использует фреймворк, который не является частью Node?
Адриан
0

loaddir - мое решение для быстрой загрузки каталога, рекурсивно.

может вернуться

{ 'path/to/file': 'fileContents...' } или { path: { to: { file: 'fileContents'} } }

Он callbackбудет вызываться при изменении файла.

Он обрабатывает ситуации, когда файлы достаточно велики, и их watchвызывают до того, как они закончат запись.

Я использовал его в проектах в течение года или около того, и только недавно добавил к нему обещания.

Помоги мне проверить это!

https://github.com/danschumann/loaddir

Funkodebat
источник
0

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

устанавливать

npm install auto-reload

пример

data.json

{ "name" : "Alan" }

test.js

var fs = require('fs');
var reload = require('auto-reload');
var data = reload('./data', 3000); // reload every 3 secs

// print data every sec
setInterval(function() {
    console.log(data);
}, 1000);

// update data.json every 3 secs
setInterval(function() {
    var data = '{ "name":"' + Math.random() + '" }';
    fs.writeFile('./data.json', data);
}, 3000);

Результат:

{ name: 'Alan' }
{ name: 'Alan' }
{ name: 'Alan' }
{ name: 'Alan' }
{ name: 'Alan' }
{ name: '0.8272748321760446' }
{ name: '0.8272748321760446' }
{ name: '0.8272748321760446' }
{ name: '0.07935990858823061' }
{ name: '0.07935990858823061' }
{ name: '0.07935990858823061' }
{ name: '0.20851597073487937' }
{ name: '0.20851597073487937' }
{ name: '0.20851597073487937' }
Lellansin
источник
0

Другое простое решение - использовать fs.readFile вместо использования require, вы можете сохранить текстовый файл, содержащий объект json, и создать интервал на сервере для перезагрузки этого объекта.

плюсы:

  • нет необходимости использовать внешние библиотеки
  • актуально для производства (перезагрузка конфигурационного файла при изменении)
  • легко реализовать

минусы:

  • Вы не можете перезагрузить модуль - просто JSON, содержащий данные значения ключа
Imri
источник
0

Для людей, использующих Vagrant и PHPStorm, средство просмотра файлов - более быстрый подход

  • отключите немедленную синхронизацию файлов, чтобы запустить команду только при сохранении, затем создать область для файлов * .js и рабочих каталогов и добавить эту команду

    vagrant ssh -c "/var/www/gadelkareem.com/forever.sh restart"

где forever.sh как

#!/bin/bash

cd /var/www/gadelkareem.com/ && forever $1 -l /var/www/gadelkareem.com/.tmp/log/forever.log -a app.js
Gadelkareem
источник
0

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

Попробовав node-mon и pm2, даже следуя их инструкциям по дополнительному просмотру папки node_modules, они все равно не получили изменений. Хотя в ответах есть несколько нестандартных решений, для чего-то подобного отдельный пакет будет чище. Я наткнулся на node-dev сегодня, и он отлично работает без каких-либо опций или настроек.

Из файла Readme:

В отличие от таких инструментов, как supervisor или nodemon, он не сканирует файловую систему для поиска файлов, которые нужно просмотреть. Вместо этого он подключается к функции Node's require () для просмотра только тех файлов, которые действительно были необходимы.

Аарон Шторк
источник
0
const cleanCache = (moduleId) => {
    const module = require.cache[moduleId];
    if (!module) {
        return;
    }
    // 1. clean parent
    if (module.parent) {
        module.parent.children.splice(module.parent.children.indexOf(module), 1);
    }
    // 2. clean self
    require.cache[moduleId] = null;
};
BottleLiu
источник
0

Вы можете сделать это с помощью обновления браузера . Приложение вашего узла перезапускается автоматически, ваша страница результатов в браузере также обновляется автоматически. Недостатком является то, что вы должны поместить фрагмент js на созданную страницу. Вот репо для рабочего примера.

const http = require('http');
const hostname = 'localhost';
const port = 3000;

const server = http.createServer((req, res) => {
    res.statusCode = 200;
    res.setHeader('Content-Type', 'text/html; charset=UTF-8');
    res.write('Simple refresh!');
    res.write(`<script src=${process.env.BROWSER_REFRESH_URL}></script>`);
    res.end();
})

server.listen(port, hostname, () => {
    console.log(`Server running at http://${hostname}:${port}/`);

    if (process.send) {
        process.send({ event: 'online', url: `http://${hostname}:${port}/` })
    }

});
Ян Пи
источник
0

Я пробовал pm2 : установка проста и удобна в использовании; результат удовлетворительный. Однако мы должны позаботиться о том, какой выпуск pm2 нам нужен. pm 2 runtime является бесплатной версией, тогда как pm2 plus и pm2 enterprise не бесплатны.

Что касается Strongloop , моя установка не удалась или не была завершена, поэтому я не мог его использовать.

Лекс Софт
источник
-1

В настоящее время используется сервер разработки WebPack с горячей опцией. Вы можете добавить такой скрипт в свой package.json:"hot": "cross-env NODE_ENV=development webpack-dev-server --hot --inline --watch-poll",

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

eKelvin
источник
2
Этот ответ неверен в отношении вопроса. Webpack предназначен для веб-приложений, а dev-сервер сам по себе является веб-сервером. Вопрос касался серверного приложения, реализованного в Node. Для этого не нужен веб-сервер. Это уже один.
DanielKhan