Як автоматично перезавантажувати файли в 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()заяві про те, що "вимагати" не визначено. process.compileзводить app.js , але не має поняття про глобальні node.js.


4
Ви знаєте, що можете просто запустити цей код у кожному запиті:Object.keys(require.cache).forEach(function(key) { delete require.cache[key]; });
Tower

Відповіді:


562

Гарною, актуальною альтернативою 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
Але в цьому випадку він також перезапустить серверний процес.
Філіпе

@Filipe, ти маєш рацію. Мене знову переадресують для входу. Я хотів би, щоб він завантажив лише той конкретний модифікований модуль
ar2015

8
automatically restart the server - perfect for developmentзанадто багато гіперболи. Перезавантаження сервера може означати вхід у сервіси, що займаються доповненнями, що в моєму випадку потребує багато часу. "Ідеально підходить для розвитку" - це щось на кшталт класів гарячої перезавантаження, коли процес працює в пам'яті, не втрачаючи стан а-ля, що робить андроїд-студія, коли ви змінюєте вихідний код.
Нуреттін

2
використовувати npm install [--save-dev | -D] nodemonдля обмеження встановлення на рамки проекту.
тематичне поле

312

вузол-супервізор надзвичайний

використання для перезавантаження при збереженні:

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

від isaacs - http://github.com/isaacs/node-supervisor


3
npm install -g супервізор. Він повинен бути встановлений у всьому світі.
Камал Редді

На OSx 10.2.8 мені довелося запустити його з
судо

2
Довелося запустити його так у Windows:"C:\Program Files\nodejs\node.exe" C:\Users\Mark\AppData\Roaming\npm\node_modules\supervisor\lib\cli-wrapper.js app.js
1313

1
без -g або Судо в додаток кореня: npm install supervisor, node node_modules/supervisor/lib/cli-wrapper.js app.js( у мене є , НЕ кореневої установки вузла)
ч-кіп

1
@Mark Це означає, що вузла немає у вашомуPATH
Blaise

88

я знайшов простий спосіб:

delete require.cache['/home/shimin/test2.js']

7
Це чудово, якщо ви хочете перезавантажити зовнішні бібліотеки без перезавантаження програми - у моєму випадку бот IRC.
Мішель Тіллі

Це чудово! Так просто і так добре працює. Щоразу, коли надходить запит, я просто знімаю кеш файлу, у якому немає стану.
воган

16
delete require.cache[require.resolve('./mymodule.js')]; вирішити справу з реальними шляхами
Едуардо

Це безпечно робити чи вважається "поганою практикою" чи "лише розвитком"?
жартівливо

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), але його можна адаптувати до декількох файлів за допомогою масиву файлів, для циклу для отримання всіх імен файлів або перегляду каталогу:

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


1
Це чудове і просте рішення. Я просто використав це для бота, який повинен був оновити себе від git, коли про це повідомив модератор. Проблема полягала в тому, що, перебуваючи в програмі, ви не можете перезапустити себе. Однак я можу використовувати ваш метод для нересурсу бота та перегляду dotfile. Потім бот оновлює себе, зачіпає dotfile і автоматично запускається пусковим пристроєм. Дивовижно!
Фред

@Fred Я радий це почути :) Я втілю це рішення в модуль, незабаром, мабуть, у мене є ще кілька ідей, як розширити його функціональність
micnic

Якщо файл watchне потрібен, перезавантаження можна зробити без fsпрослуховування різного сигналу.
Володимир

18

nodemon вийшов першим у пошуку в Google, і, здається, зробив свою справу:

npm install nodemon -g
cd whatever_dir_holds_my_app
nodemon app.js

8

Є Node-Supervisor, який ви можете встановити

npm install supervisor

див. http://github.com/isaacs/node-supervisor


2
Йдеться більше про перезапуск сервера, якщо він виходить з ладу. node-supervisor також перезавантажує весь процес, коли переглянуті файли були змінені. Це не гаряча перезавантаження в строгому сенсі.
nalply

Хоча це не дуже гаряча завантаження, цей інструмент дуже корисний, якщо ви просто хочете, щоб код автоматично завантажувався під час розробки, тому вам не доведеться перезавантажувати вузол у командному рядку після кожної зміни.
Дерек Дамер

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, але я над цим працюю зараз.


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як розробник залежність проекту. Тож членам вашої команди не потрібно її встановлювати або запам'ятати аргументи команд, вони простоnpm run dev і починають злом.

Більше про nodemonдокументи: https://github.com/remy/nodemon#monitoring-multiple-directories


Globbing не підтримується для останніх версій nodemon (принаймні 1.19.0). Просто використовуйте замість nodemon --watch server --inspect ./server/server.js.
Олексій

Дякуємо @Alex за вашу інформацію. Оновлено відповідь.
Нін Фам

5

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


1
+1 Так. Я брав участь у дискусії. Я визнав, що моє рішення занадто просте. Він працює лише в тому випадку, якщо сам гарячий модуль не потребує додаткових модулів. Рішення Фелікса є більш продуманим, але воно обговорюється, якщо автоматичне завантаження дійсно належить до ядра.
nalply

5

ще одне рішення цієї проблеми використовується назавжди

Ще одна корисна можливість Forever полягає в тому, що він може необов'язково перезапустити додаток, коли змінилися будь-які вихідні файли. Це звільняє вас від необхідності вручну перезапускати щоразу, коли ви додаєте функцію чи виправляєте помилку. Щоб запустити назавжди в цьому режимі, використовуйте прапор -w:

forever -w start server.js

Як не дивно, коли прапор -w мій додаток express.js не використовує CSS.
Коста

5

node-dev чудово працює. п / хвinstall node-dev

Він навіть дає сповіщення на робочому столі, коли сервер буде перезавантажений і дасть успіх або помилки в повідомленні.

запустіть додаток у командному рядку з:

node-dev app.js


3

Ось повідомлення в блозі про Hot Reloading для Node. Він забезпечує гілку Github 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

Я працюю над тим, щоб створити досить крихітну «річ» вузла, яка здатна завантажувати / вивантажувати модулі за бажанням (так, тобто ви зможете перезапустити частину програми, не збиваючи весь додаток). Я включаю (дуже дурне) управління залежністю, так що якщо ви хочете зупинити модуль, всі модулі, які залежать від цього, теж будуть зупинені.

Поки що добре, але потім я натрапив на питання, як перезавантажити модуль. Мабуть, можна було просто вийняти модуль з кешу "вимагати" і виконати роботу. Оскільки я не бажаю безпосередньо змінювати вихідний код вузла, я придумав дуже хакі-хак: пошук у сліді стека останній виклик функції "вимагати", схопити посилання на поле "кеш" і ... добре, видаліть посилання на вузол:

    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"], але він робить свою роботу. Я вірю, що хлопці із вузлів колись запровадять інструмент перезавантаження, тому я думаю, що наразі це рішення також прийнятне. (btw. моя "річ" буде тут: https://github.com/cheng81/wirez , зайдіть туди через пару тижнів, і ви повинні побачити, про що я говорю)


.. звичайно, це не так просто. Це працює тільки якщо є виклик вимагає в стеці викликів. Ну добре, легкий хак на вершині хака: запишіть цей матеріал у темп-сценарії та вимагайте його під час виконання. Зробив це, він працює ... і навіть очистився від кеша
cheng81

А насправді було простіше: видалити (Requ.cache [moduleFullpathAndExt])
cheng81

Модулі Node.js насправді загорнуті в анонімну функцію, якою робиться інкапсуляція модуля. Кожен модуль насправді виглядає так function (module, require) { /* your code */ }. Коли ви це враховуєте, arguments[1]вказуйте на require. І цикл while є для ситуацій, коли ви викликаєте це з іншої функції модуля (він просто піднімає ієрархію функцій і перевіряє значення аргументів, передані кожному).
JK

3

Можна використовувати nodemon від NPM . І якщо ви використовуєте генератор експресів, ви можете використовувати цю команду всередині вашої папки проекту:

nodemon npm start

або в режимі налагодження

DEBUG=yourapp:* nodemon npm start

ви також можете запустити безпосередньо

nodemon your-app-file.js

Сподіваюся, що це допоможе.


1

рішення за адресою: http://github.com/shimondoodkin/node-hot-reload

зауважте, що вам потрібно подбати про власні посилання.

це означає, що якщо ви зробили: var x = requ ('foo'); y = x; z = x.bar; і гаряче перезавантажив його.

це означає, що вам доведеться замінити посилання, що зберігаються в x, y і z. в функції гарячого повторного завантаження виклику.

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

Також мені подобається мій модуль надходження вузлів.


1

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

Ймовірно , краще всього один IntelliJ WebStorm з гарячою функцією перезавантаження (автоматичний сервер і браузер перезавантаженням) для Node.js .


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" в оболонці cmd.


1

моя структура додатків:

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

спочатку встановіть перезавантаження за допомогою цієї команди:

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

потім змініть package.json :

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

тепер ви повинні використовувати перезавантаження у вашому файлі сервера :

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");

І конфігурація автоматично перезавантажується :)


Отримала версію, яка не покладається на рамки, що не входять до Node?
Адріан

0

loaddir - це моє рішення для швидкого завантаження каталогу, рекурсивно.

може повернутися

{ 'path/to/file': 'fileContents...' } або { path: { to: { file: 'fileContents'} } }

Це має callback який буде викликаний, коли файл буде змінено.

Він обробляє ситуації, коли файли достатньо великі, що watchвикликає, перш ніж вони закінчують запис.

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

Допоможіть мені бойовий тест!

https://github.com/danschumann/loaddir


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' }

0

Ще одне просте рішення - використовувати fs.readFile замість використання вимагає ви можете зберегти текстовий файл, що стосується об’єкта json, та створити на сервері інтервал для перезавантаження цього об’єкта.

плюси:

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

мінуси:

  • ви не можете перезавантажити модуль - лише json, що містить дані ключових значень

0

Для людей, які використовують Vagrant та PHPStorm, спостерігач файлів - це швидший підхід

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

    vagrant ssh -c "/var/www/gadelkareem.com/forever.sh перезапуск"

де назавжди.ш як

#!/bin/bash

cd /var/www/gadelkareem.com/ && forever $1 -l /var/www/gadelkareem.com/.tmp/log/forever.log -a app.js

0

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

Спробувавши node-mon та pm2, навіть дотримуючись їх інструкцій щодо додаткового перегляду папки node_modules, вони все ще не підбирали зміни. Хоча тут є відповіді на деякі власні рішення, для чогось подібного окремий пакет є чистішим. Сьогодні я натрапив на node-dev, і він ідеально працює без будь-яких параметрів чи налаштувань.

З Readme:

На відміну від таких інструментів, як супервізор чи nodemon, він не сканує файлову систему на предмет перегляду файлів. Натомість він підключається до функції вимагає () Node для перегляду лише потрібних файлів.


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;
};

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 час виконання - це безкоштовне видання, тоді як pm2 плюс та pm2 підприємство не безкоштовне.

Що стосується Strongloop , то моя установка не вдалася або не була завершена, тому я не міг її використовувати.


-1

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

і кожна зміна ваших файлів автоматично призведе до перекомпіляції


2
Ця відповідь неправильна, тому що питання. Вебпак призначений для програм із інтерфейсом, а сервер розробників - самостійно веб-сервер. Питання стосувалося серверної програми, реалізованої в Node. Для цього не потрібен веб-сервер. Це вже одне.
DanielKhan
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.