Come ricaricare automaticamente i file in Node.js?


444

Qualche idea su come potrei implementare un ricaricamento automatico dei file in Node.js? Sono stanco di riavviare il server ogni volta che cambio un file. Apparentemente la require()funzione di Node.js non ricarica i file se sono già stati richiesti, quindi devo fare qualcosa del genere:

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

E nel file app.js ho:

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

Ma anche questo non funziona: viene visualizzato un errore process.compile()nell'affermazione che dice che "richiede" non è definito. process.compilesta valutando app.js , ma non ha idea dei globali node.js.


4
Sai che puoi semplicemente eseguire questo codice su ogni richiesta:Object.keys(require.cache).forEach(function(key) { delete require.cache[key]; });
Torre

Risposte:


564

Un'alternativa valida e aggiornata a supervisorè nodemon:

Monitora eventuali modifiche nell'applicazione node.js e riavvia automaticamente il server, perfetto per lo sviluppo

Per usare nodemon:

$ npm install nodemon -g
$ nodemon app.js

2
e se vuoi usarlo in Nitrous.io - $ nodemon -L yourfile.js(spiegazione completa su coderwall.com/p/aqxl_q )
drzaus,

3
Ma in questo caso, riavvia anche il processo del server.
Filipe,

@Filipe, hai ragione. Sono reindirizzato per accedere di nuovo. Vorrei che caricasse solo quel modulo modificato specifico.
ar2015,

8
automatically restart the server - perfect for developmentè troppo iperbole. Ricaricare il server potrebbe significare accedere ai servizi di back-end, il che nel mio caso richiede molto tempo. "Perfetto per lo sviluppo" sarebbe qualcosa come le classi di ricarica a caldo mentre il processo è in esecuzione in memoria senza perdere stato a ciò che fa Android Studio quando si modifica il codice sorgente.
Nurettin,

2
utilizzare npm install [--save-dev | -D] nodemonper limitare l'installazione all'ambito del progetto.
themefield,

312

il supervisore dei nodi è fantastico

utilizzo per riavviare al salvataggio:

npm install supervisor -g
supervisore app.js

di isaacs - http://github.com/isaacs/node-supervisor


3
npm install -g supervisore. Dovrebbe essere installato a livello globale.
Kamal Reddy,

Su OSx 10.2.8 ho dovuto eseguirlo con sudo
Timopheym il

2
Ho dovuto eseguirlo in questo modo su Windows:"C:\Program Files\nodejs\node.exe" C:\Users\Mark\AppData\Roaming\npm\node_modules\supervisor\lib\cli-wrapper.js app.js
mpen

1
senza -g o sudo alla radice app: npm install supervisor, node node_modules/supervisor/lib/cli-wrapper.js app.js(ho un'installazione non root del Nodo)
h-Kippo

1
@Mark Questo significa che il nodo non è nel tuoPATH
Blaise,

88

ho trovato un modo semplice:

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

7
Questo è fantastico se vuoi ricaricare librerie esterne senza riavviare l'app - nel mio caso, un bot IRC.
Michelle Tilley,

Questo è eccellente! Così semplice e funziona così bene. Ogni volta che arriva una richiesta, deseleziono solo un mucchio di file che non mantengono lo stato.
vaughan,

16
delete require.cache[require.resolve('./mymodule.js')]; risolvere l'affare con percorsi reali
Eduardo,

È sicuro fare o considerare "cattive pratiche" o "solo sviluppo"?
Giovedì

2
@jocull Non penso sia sicuro, dal momento che può ricreare classi e funzioni o qualunque esportazione, risultando in riferimenti diversi se confrontati con===
Kroltan

20

Se qualcuno continua a rispondere a questa domanda e desidera risolverla utilizzando solo i moduli standard, ho fatto un semplice esempio:

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

Questo esempio è solo per un file (server.js), ma può essere adattato a più file utilizzando una matrice di file, un ciclo for per ottenere tutti i nomi di file o guardando una directory:

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

Questo codice è stato creato per l'API Node.js 0.8, non è adattato per alcune esigenze specifiche ma funziona in alcune semplici app.

AGGIORNAMENTO: Questa funzione è implementata nel mio modulo simpleR , repository GitHub


1
Questa è una soluzione grande e semplice. L'ho usato solo per un bot che avrebbe dovuto aggiornarsi da Git quando glielo ha detto un moderatore. Il problema era che una volta entrati nell'app non è possibile riavviarsi. Posso, tuttavia, usare il tuo metodo per generare un'istanza del bot e guardare un file dot. Il bot quindi si aggiorna, tocca il dotfile e verrà riavviato automaticamente dal programma di avvio. Eccezionale!
Fred

@Fred Sono felice di sentirlo :) Implementerò questa soluzione in un modulo, presto immagino, ho qualche idea in più su come espandere la sua funzionalità
micnic

Se il file watchnon è necessario, è possibile ricaricare senza fsascoltare un segnale diverso.
Vladimir Vukanac,

18

nodemon è arrivato prima in una ricerca su google e sembra fare il trucco:

npm install nodemon -g
cd whatever_dir_holds_my_app
nodemon app.js

8

C'è Node-Supervisor che puoi installare

npm install supervisor

vedi http://github.com/isaacs/node-supervisor


2
Si tratta di riavviare il server in caso di crash. Anche il supervisore dei nodi riavvia l'intero processo quando i file controllati sono stati modificati. Non è hot-ricaricare in senso stretto.
nalply,

Sebbene non sia un caricamento a caldo, questo strumento è davvero utile se vuoi solo che il codice si ricarichi automaticamente durante lo sviluppo, quindi non devi riavviare il nodo nella riga di comando dopo ogni modifica.
Derek Dahmer,

7

Modifica: la mia risposta è obsoleta. Node.js è una tecnologia in rapida evoluzione.

Mi chiedevo anche di ricaricare i moduli. Ho modificato node.js e ho pubblicato la fonte su Github su nalply / node . L'unica differenza è la funzione require. Ha un secondo argomento facoltativo reload.

require(url, reload)

Per ricaricare app.jsnella directory corrente utilizzare

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

Scrivi qualcosa del genere e hai auto- ricaricare:

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

L'unico problema che vedo è la variabile module, ma ci sto lavorando ora.


7

nodemonè fantastico. Aggiungo solo altri parametri per il debug e le opzioni di visualizzazione.

package.json

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

Il comando: nodemon --watch server --inspect ./server/server.js

Mentre:

--watch serverRiavviare l'applicazione quando si cambia .js, .mjs, .coffee, .litcoffee, e.json file nella servercartella (comprese le sottocartelle).

--inspect Abilita debug remoto.

./server/server.js Il punto di ingresso.

Quindi aggiungere la seguente configurazione a launch.json(Codice VS) e iniziare il debug in qualsiasi momento.

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

Si noti che è meglio installare nodemoncome dipendenza dev del progetto. Quindi i membri del tuo team non devono installarlo o ricordare gli argomenti del comando, semplicementenpm run dev iniziano e iniziano a hackerare.

Ulteriori informazioni sui nodemondocumenti: https://github.com/remy/nodemon#monitoring-multiple-directories


Globbing non è supportato per le versioni recenti di nodemon (almeno 1.19.0). Basta usare nodemon --watch server --inspect ./server/server.js invece.
Alex

Grazie @Alex per le tue informazioni. Aggiornato la risposta.
Ninh Pham,

5

C'è stato un thread recente su questo argomento nella mailing list node.js. La risposta breve è no, al momento non è possibile ricaricare automaticamente i file richiesti, ma diverse persone hanno sviluppato patch che aggiungono questa funzione.


1
+1 Sì. Ho partecipato alla discussione. Ho ammesso che la mia soluzione è troppo semplice. Funziona solo se il modulo caldo stesso non richiede ulteriori moduli. La soluzione di Felix è più ben congegnata ma viene discussa se il ricaricamento automatico appartiene davvero al nocciolo.
nalply

5

ancora un'altra soluzione per questo problema sta usando per sempre

Un'altra utile funzionalità di Forever è che può facoltativamente riavviare l'applicazione quando vengono modificati i file di origine. Questo ti libera dal dover riavviare manualmente ogni volta che aggiungi una funzione o correggi un bug. Per avviare Forever in questa modalità, utilizzare il flag -w:

forever -w start server.js

Stranamente con la bandiera -w la mia app express.js non usa CSS.
Costa,

5

node-dev funziona alla grande. npminstall node-dev

Dà anche una notifica desktop quando il server viene ricaricato e darà esito positivo o errori sul messaggio.

avvia la tua app dalla riga di comando con:

node-dev app.js


3

Ecco un post sul blog su Hot Reloading for Node. Fornisce un ramo Nodo github che è possibile utilizzare per sostituire l'installazione di Nodo per abilitare Ricaricamento a caldo.

Dal blog:

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

Ora, ogni volta che modifichi myRequestHandler.js, il codice sopra noterà e sostituirà il requestHandler locale con il nuovo codice. Eventuali richieste esistenti continueranno a utilizzare il vecchio codice, mentre eventuali nuove richieste in arrivo utilizzeranno il nuovo codice. Tutto senza arrestare il server, far rimbalzare qualsiasi richiesta, uccidere prematuramente qualsiasi richiesta o persino fare affidamento su un bilanciamento del carico intelligente.


L'unica cosa con questa soluzione è che è un fork di una versione precedente di Node, quindi dovrà essere ottimizzato e unito all'ultima versione prima dell'uso (a meno che non ti dispiaccia usare una versione precedente di Node).
Chetan,

3

Sto lavorando per creare una "cosa" di nodo piuttosto piccola che sia in grado di caricare / scaricare i moduli a piacimento (quindi, ad esempio, potresti essere in grado di riavviare parte della tua applicazione senza mettere giù l'intera app). Sto incorporando una (molto stupida) gestione delle dipendenze, in modo che se si desidera arrestare un modulo, anche tutti i moduli che dipendono da questo verranno arrestati.

Fin qui tutto bene, ma poi mi sono imbattuto nel problema di come ricaricare un modulo. Apparentemente, si potrebbe semplicemente rimuovere il modulo dalla cache "richiedi" e fare il lavoro. Dato che non sono disposto a cambiare direttamente il codice sorgente del nodo, ho trovato un hack molto caotico che è: cerca nello stack traccia l'ultima chiamata alla funzione "richiesta", prendi un riferimento al suo campo "cache" e ... beh, cancella il riferimento al nodo:

    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 ] )

Ancora più semplice, in realtà:

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

Apparentemente, funziona perfettamente. Non ho assolutamente idea di cosa significhino questi argomenti ["1"], ma sta facendo il suo lavoro. Credo che i ragazzi del nodo implementeranno un giorno una struttura di ricarica, quindi suppongo che per ora anche questa soluzione sia accettabile. (a proposito. la mia "cosa" sarà qui: https://github.com/cheng81/wirez , andateci tra un paio di settimane e dovreste vedere di cosa sto parlando)


.. ovviamente non è così semplice. Funziona solo se c'è una chiamata da richiedere nello stack di chiamate. Vabbè, hack facile sopra un hack: scrivi quella roba in uno script temporaneo e richiedila in fase di esecuzione. Lo ha fatto, funziona..e si è persino ripulito dalla cache
cheng81

E in realtà è stato più semplice: delete (require.cache [moduleFullpathAndExt])
cheng81

I moduli Node.js sono effettivamente racchiusi in una funzione anonima che è come viene fatto l'incapsulamento del modulo. Ogni modulo in realtà sembra function (module, require) { /* your code */ }. Quando lo prendi in considerazione, arguments[1]punta a require. E il ciclo while è lì per le situazioni in cui lo chiamate da un'altra funzione in un modulo (sale semplicemente nella gerarchia delle funzioni e controlla i valori degli argomenti passati a ciascuna).
JK,

3

È possibile utilizzare nodemon da NPM . E se si utilizza Express generator, è possibile utilizzare questo comando nella cartella del progetto:

nodemon npm start

o usando la modalità Debug

DEBUG=yourapp:* nodemon npm start

puoi anche eseguire direttamente

nodemon your-app-file.js

Spero che questo aiuto.


1

soluzione a: http://github.com/shimondoodkin/node-hot-reload

nota che devi prenderti cura dei riferimenti utilizzati.

ciò significa che se lo hai fatto: var x = request ('pippo'); y = x; z = x.bar; e caldo lo ha ricaricato.

significa che devi sostituire i riferimenti memorizzati in x, ye z. nella funzione di richiamata hot-load.

alcune persone confondono la ricarica a caldo con il riavvio automatico il mio modulo nodejs-autorestart ha anche l'integrazione di avvio per abilitare l'avvio automatico all'avvio. se hai una piccola app il riavvio automatico va bene, ma quando hai una grande app la ricarica a caldo è più adatta. semplicemente perché la ricarica a caldo è più veloce.

Mi piace anche il mio modulo di afflusso di nodi.


1

Non è necessario utilizzare nodemon o altri strumenti simili. Usa le funzionalità del tuo IDE.

Probabilmente migliore è IntelliJ WebStorm con funzione di ricarica a caldo (automatico del server e aggiornare il browser) per node.js .


1

Ecco un metodo a bassa tecnologia per l'uso in Windows. Metti questo in un file batch chiamato serve.bat:

@echo off

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

Ora invece di correre node app.jsdalla tua shell cmd, corri serve app.js.

Questo aprirà una nuova finestra della shell che esegue il server. Il file batch verrà bloccato (a causa del/wait ) fino a quando non si chiude la finestra della shell, a quel punto la shell cmd originale chiederà "Termina processo batch (S / N)?" Se si risponde "N", il server verrà riavviato.

Ogni volta che si desidera riavviare il server, chiudere la finestra del server e rispondere "N" nella shell cmd.


1

la mia struttura dell'app:

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

prima installazione ricaricare con questo comando:

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

quindi cambia package.json :

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

ora è necessario utilizzare ricaricare nel file del server :

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

e per l'ultima modifica, fine della tua risposta invia questo script :

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

ora avvia la tua app con questo codice:

npm start

Questo approccio non funziona, tuttavia quelli indicati in npmjs.com/package/reload (per le app Express) lo fanno.
Maxie Berkmann il

0

Usa questo:

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

Tutto quello che devi fare ora è:

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

E la configurazione verrà ricaricata automaticamente :)


Hai una versione che non si basa su un framework che non fa parte di Node?
Adrian,

0

loaddir è la mia soluzione per il caricamento rapido di una directory, in modo ricorsivo.

può tornare

{ 'path/to/file': 'fileContents...' } o { path: { to: { file: 'fileContents'} } }

Esso ha callback quale verrà chiamato quando il file viene modificato.

Gestisce situazioni in cui i file sono abbastanza grandi da essere watchchiamati prima che abbiano finito di scrivere.

Lo sto usando in progetti da circa un anno, e recentemente ho aggiunto promesse.

Aiutami a combattere testarlo!

https://github.com/danschumann/loaddir


0

È possibile utilizzare il ricaricamento automatico per ricaricare il modulo senza arrestare il server.

installare

npm install auto-reload

esempio

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

Risultato:

{ 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

un'altra semplice soluzione è usare fs.readFile invece di usare request è possibile salvare un file di testo contenente un oggetto json e creare un intervallo sul server per ricaricare questo oggetto.

professionisti:

  • non c'è bisogno di usare librerie esterne
  • rilevante per la produzione (ricaricare il file di configurazione in caso di modifica)
  • facile da implementare

contro:

  • non è possibile ricaricare un modulo - solo un json contenente dati chiave-valore

0

Per le persone che usano Vagrant e PHPStorm, il file watcher è un approccio più veloce

  • disabilita la sincronizzazione immediata dei file in modo da eseguire il comando solo al momento del salvataggio, quindi creare un ambito per i file * .js e le directory di lavoro e aggiungere questo comando

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

dove forever.sh è come

#!/bin/bash

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

0

Di recente sono arrivato a questa domanda perché i soliti sospetti non stavano lavorando con i pacchetti collegati. Se sei come me e ne stai approfittando npm linkdurante lo sviluppo per lavorare efficacemente su un progetto composto da molti pacchetti, è importante che anche i cambiamenti che si verificano nelle dipendenze innescino un ricaricamento.

Dopo aver provato node-mon e pm2, anche seguendo le loro istruzioni per guardare ulteriormente la cartella node_modules, non hanno ancora raccolto le modifiche. Sebbene ci siano alcune soluzioni personalizzate nelle risposte qui, per qualcosa del genere, un pacchetto separato è più pulito. Mi sono imbattuto in node-dev oggi e funziona perfettamente senza alcuna opzione o configurazione.

Dal file Leggimi:

A differenza di strumenti come supervisore o nodemon, non esegue la scansione del file system alla ricerca di file. Invece si aggancia alla funzione necess () di Node per guardare solo i file che sono stati effettivamente richiesti.


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

Puoi farlo con l' aggiornamento del browser . L'app del nodo si riavvia automaticamente, anche la pagina dei risultati nel browser si aggiorna automaticamente. Unico inconveniente è che devi inserire lo snippet js nella pagina generata. Ecco il repository per l'esempio funzionante.

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

Ho provato pm2 : anche l'installazione è facile e facile da usare; il risultato è soddisfacente. Tuttavia, dobbiamo occuparci dell'edizione di pm2 che vogliamo. pm 2 runtime è l'edizione gratuita, mentre pm2 plus e pm2 enterprise non sono gratuiti.

Per quanto riguarda Strongloop , la mia installazione non è riuscita o non è stata completata, quindi non ho potuto utilizzarla.


-1

Oggi viene utilizzato il server di sviluppo WebPack con l'opzione hot. puoi aggiungere uno script come questo nel tuo package.json:"hot": "cross-env NODE_ENV=development webpack-dev-server --hot --inline --watch-poll",

e ogni modifica nei tuoi file attiverà automaticamente una ricompilazione


2
Questa risposta è errata nella domanda. Webpack è per applicazioni front-end e il server dev è un server web a sé stante. La domanda si riferiva a un'applicazione server implementata in Node. Non ha bisogno di un server web. Lo è già.
DanielKhan,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.