Comment recharger automatiquement les fichiers dans Node.js?

444

Des idées sur la façon dont je pourrais implémenter une recharge automatique des fichiers dans Node.js? J'en ai assez de redémarrer le serveur à chaque fois que je change un fichier. Apparemment, la require()fonction de Node.js ne recharge pas les fichiers s'ils ont déjà été requis, donc je dois faire quelque chose comme ceci:

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

Et dans le fichier app.js j'ai:

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

Mais cela ne fonctionne pas non plus - je reçois une erreur dans la process.compile()déclaration disant que «exiger» n'est pas défini. process.compileévalue app.js , mais n'a aucune idée des globaux node.js.

disc0dancer
la source
4
Vous savez que vous pouvez simplement exécuter ce code à chaque demande:Object.keys(require.cache).forEach(function(key) { delete require.cache[key]; });
Tower

Réponses:

564

Une bonne alternative à jour supervisorest nodemon:

Surveillez les changements dans votre application node.js et redémarrez automatiquement le serveur - parfait pour le développement

Pour utiliser nodemon:

$ npm install nodemon -g
$ nodemon app.js
Marius Butuc
la source
2
et si vous voulez l'utiliser dans Nitrous.io - $ nodemon -L yourfile.js(explication complète sur coderwall.com/p/aqxl_q )
drzaus
3
Mais dans ce cas, il redémarre également le processus serveur.
Filipe
@Filipe, vous avez raison. Je suis redirigé pour me reconnecter. Je souhaite qu'il ne charge que ce module modifié spécifique.
ar2015
8
automatically restart the server - perfect for developmentc'est beaucoup trop d'hyperbole. Le rechargement du serveur pourrait signifier la connexion aux services backend, ce qui prend beaucoup de temps dans mon cas. «Parfait pour le développement» serait quelque chose comme des classes de rechargement à chaud pendant que le processus s'exécute en mémoire sans perdre l'état comme le fait Android Studio lorsque vous changez le code source.
nurettin
2
utiliser npm install [--save-dev | -D] nodemonpour limiter l'installation à la portée du projet.
themefield
312

le superviseur de nœud est génial

utilisation pour redémarrer lors de la sauvegarde:

npm install supervisor -g
superviseur app.js

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

Anup Bishnoi
la source
3
npm install -g superviseur. Il doit être installé à l'échelle mondiale.
Kamal Reddy
Sur OSx 10.2.8, je devais l'exécuter avec sudo
Timopheym
2
J'ai dû l'exécuter comme ça sous Windows:"C:\Program Files\nodejs\node.exe" C:\Users\Mark\AppData\Roaming\npm\node_modules\supervisor\lib\cli-wrapper.js app.js
mpen
1
sans -g ou à la racine de sudo app: npm install supervisor, node node_modules/supervisor/lib/cli-wrapper.js app.js(j'ai une installation non root du nœud)
h-Kippo
1
@Mark Cela signifie que le nœud n'est pas dans votrePATH
Blaise
88

j'ai trouvé un moyen simple:

delete require.cache['/home/shimin/test2.js']
Inshua
la source
7
C'est génial si vous souhaitez recharger des bibliothèques externes sans redémarrer l'application - dans mon cas, un bot IRC.
Michelle Tilley
C'est excellent! Si simple et fonctionne si bien. Chaque fois qu'une demande arrive, je détache juste un tas de fichiers qui ne contiennent pas d'état.
vaughan
16
delete require.cache[require.resolve('./mymodule.js')]; résoudre un problème avec des chemins réels
Eduardo
Est-ce sûr à faire ou considéré comme une «mauvaise pratique» ou un «développement uniquement»?
jocull
2
@jocull Je ne pense pas que ce soit sûr, car il peut recréer des classes et des fonctions ou tout autre export, entraînant des références différentes lors de la comparaison avec===
Kroltan
20

Si quelqu'un vient encore à cette question et veut la résoudre en utilisant uniquement les modules standard, j'ai fait un exemple simple:

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

Cet exemple ne concerne qu'un seul fichier (server.js), mais peut être adapté à plusieurs fichiers en utilisant un tableau de fichiers, une boucle for pour obtenir tous les noms de fichiers ou en regardant un répertoire:

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

Ce code a été conçu pour l'API Node.js 0.8, il n'est pas adapté à certains besoins spécifiques mais fonctionnera dans certaines applications simples.

MISE À JOUR: Cette fonctionnalité est implémentée dans mon module simpleR , GitHub repo

micnic
la source
1
Il s'agit d'une excellente solution simple. Je viens de l'utiliser pour un bot qui était censé se mettre à jour à partir de git quand un modérateur le lui a dit. Le problème était qu'une fois que vous êtes dans l'application, vous ne pouvez pas redémarrer vous-même. Je peux cependant utiliser votre méthode pour générer une instance du bot et regarder un fichier dot. Le bot se met ensuite à jour, touche le fichier dot et sera automatiquement redémarré par le lanceur. Impressionnant!
Fred
@Fred je suis content d'entendre cela :) Je vais implémenter cette solution dans un module, bientôt je suppose, j'ai quelques idées pour étendre ses fonctionnalités
micnic
Si le fichier watchn'est pas nécessaire, le rechargement peut se faire sans fs, en écoutant un signal différent.
Vladimir Vukanac
18

nodemon est apparu en premier dans une recherche google, et il semble faire l'affaire:

npm install nodemon -g
cd whatever_dir_holds_my_app
nodemon app.js
JnBrymn
la source
8

Il y a Node-Supervisor que vous pouvez installer en

npm install supervisor

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

Richard Metzler
la source
2
Il s'agit davantage de redémarrer le serveur en cas de panne. node-supervisor redémarre également l'ensemble du processus lorsque les fichiers surveillés ont été modifiés. Il ne s'agit pas d'un rechargement à chaud au sens strict.
2010
Bien qu'il ne soit pas vraiment chargé à chaud, cet outil est vraiment utile si vous voulez simplement que le code se recharge automatiquement pendant que vous développez, vous n'avez donc pas à redémarrer le nœud dans la ligne de commande après chaque modification.
Derek Dahmer
7

Edit: Ma réponse est obsolète. Node.js est une technologie qui évolue très rapidement.

Je me suis également interrogé sur le rechargement des modules. J'ai modifié node.js et j'ai publié la source sur Github à nalply / node . La seule différence est la fonction require. Il a un deuxième argument facultatif reload.

require(url, reload)

Pour recharger app.jsdans le répertoire courant, utilisez

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

Écrivez quelque chose comme ça, et vous avez le rechargement automatique :

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

Le seul problème que je vois est la variable module, mais j'y travaille maintenant.

nalply
la source
7

nodemonest un grand. J'ajoute juste plus de paramètres pour les options de débogage et d'observation.

package.json

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

La commande: nodemon --watch server --inspect ./server/server.js

Tandis que:

--watch serverRedémarrez l'application lors d'un changement .js, .mjs, .coffee, .litcoffeeet les .jsonfichiers dans le serverdossier (sous - dossiers inclus).

--inspect Activez le débogage à distance.

./server/server.js Le point d'entrée.

Ajoutez ensuite la configuration suivante à launch.json(VS Code) et commencez le débogage à tout moment.

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

Notez qu'il est préférable d'installer en nodemontant que dépendance dev du projet. Ainsi, les membres de votre équipe n'ont pas besoin de l'installer ni de se souvenir des arguments de la commande, ils npm run devcommencent simplement et commencent à pirater.

En savoir plus sur les nodemondocuments: https://github.com/remy/nodemon#monitoring-multiple-directories

Ninh Pham
la source
La globalisation n'est pas prise en charge pour les versions récentes de nodemon (1.19.0 au moins). Utilisez simplement nodemon --watch server --inspect ./server/server.js à la place.
Alex
Merci @Alex pour vos informations. Mis à jour la réponse.
Ninh Pham
5

Il y avait un fil récent sur ce sujet dans la liste de diffusion node.js. La réponse courte est non, il n'est actuellement pas possible de recharger automatiquement les fichiers requis, mais plusieurs personnes ont développé des correctifs qui ajoutent cette fonctionnalité.

Xavi
la source
1
+1 Oui. J'ai participé à la discussion. J'ai admis que ma solution est trop simple. Cela ne fonctionne que si le module chaud lui-même ne nécessite pas de modules supplémentaires. La solution de Felix est plus réfléchie mais elle est débattue si le rechargement automatique appartient vraiment au noyau.
nalply
5

encore une autre solution à ce problème utilise pour toujours

Une autre fonctionnalité utile de Forever est qu'il peut éventuellement redémarrer votre application lorsque des fichiers source ont été modifiés. Cela vous évite d'avoir à redémarrer manuellement chaque fois que vous ajoutez une fonctionnalité ou corrigez un bogue. Pour démarrer Forever dans ce mode, utilisez l'indicateur -w:

forever -w start server.js
Teoman shipahi
la source
Étrangement avec le drapeau -w, mon application express.js n'utilise pas CSS.
Costa
5

node-dev fonctionne très bien. npminstall node-dev

Il donne même une notification de bureau lorsque le serveur est rechargé et donnera le succès ou les erreurs sur le message.

démarrez votre application en ligne de commande avec:

node-dev app.js

l3o
la source
3

Voici un article de blog sur le rechargement à chaud pour le nœud. Il fournit une branche github Node que vous pouvez utiliser pour remplacer votre installation de Node afin d'activer le rechargement à chaud.

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

Maintenant, chaque fois que vous modifiez myRequestHandler.js, le code ci-dessus remarquera et remplacera le requestHandler local par le nouveau code. Toutes les demandes existantes continueront d'utiliser l'ancien code, tandis que toutes les nouvelles demandes entrantes utiliseront le nouveau code. Le tout sans arrêter le serveur, faire rebondir toutes les demandes, tuer prématurément toutes les demandes ou même compter sur un équilibreur de charge intelligent.

Chétan
la source
La seule chose avec cette solution est que c'est un fork d'une ancienne version de Node, donc il devra être modifié et fusionné avec la dernière version avant de l'utiliser (sauf si cela ne vous dérange pas d'utiliser une ancienne version de Node).
Chetan
3

Je travaille sur la création d'une "chose" de nœud assez petite qui est capable de charger / décharger des modules à volonté (donc, vous pourriez être en mesure de redémarrer une partie de votre application sans arrêter l'application entière). J'incorpore une gestion des dépendances (très stupide), de sorte que si vous voulez arrêter un module, tous les modules qui en dépendent seront également arrêtés.

Jusqu'ici tout va bien, mais ensuite je suis tombé sur la question de savoir comment recharger un module. Apparemment, on pourrait simplement supprimer le module du cache "require" et faire le travail. Comme je ne souhaite pas changer directement le code source du nœud, j'ai trouvé un hack très hacky qui est: recherchez dans la pile tracez le dernier appel à la fonction "require", récupérez une référence à son champ "cache" et..bien, supprimez la référence au nœud:

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

Encore plus facile, en fait:

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

Apparemment, cela fonctionne très bien. Je n'ai absolument aucune idée de ce que signifie cet argument ["1"], mais il fait son travail. Je crois que les gars du nœud implémenteront un jour une fonction de rechargement, donc je suppose que pour l'instant cette solution est également acceptable. (btw. mon "truc" sera ici: https://github.com/cheng81/wirez , allez-y dans quelques semaines et vous devriez voir de quoi je parle)

cheng81
la source
..bien sûr, ce n'est pas si simple. Cela ne fonctionne que s'il y a un appel à exiger dans la pile d'appels. Eh bien, piratage facile au-dessus d'un piratage: écrivez ce truc dans un script temporaire, et exigez-le au moment de l'exécution. Je l'ai fait, ça fonctionne ... et il s'est même nettoyé du cache
cheng81
Et en fait, c'était plus facile: supprimer (require.cache [moduleFullpathAndExt])
cheng81
Les modules Node.js sont en fait enveloppés dans une fonction anonyme qui est la façon dont l'encapsulation du module est effectuée. Chaque module ressemble en fait function (module, require) { /* your code */ }. Lorsque vous en tenez compte, arguments[1]pointez sur require. Et la boucle while est là pour les situations où vous appelez cela à partir d'une autre fonction d'un module (elle remonte simplement la hiérarchie des fonctions et vérifie les valeurs d'argument transmises à chacune).
JK
3

Vous pouvez utiliser nodemon de NPM . Et si vous utilisez le générateur Express, vous pouvez utiliser cette commande dans votre dossier de projet:

nodemon npm start

ou en utilisant le mode débogage

DEBUG=yourapp:* nodemon npm start

vous pouvez également exécuter directement

nodemon your-app-file.js

J'espère que cette aide.

azwar_akbar
la source
1

solution sur: http://github.com/shimondoodkin/node-hot-reload

notez que vous devez faire vous-même attention aux références utilisées.

cela signifie que si vous l'avez fait: var x = require ('foo'); y = x; z = x.bar; et rechargé à chaud.

cela signifie que vous devez remplacer les références stockées dans x, y et z. dans la fonction de rappel à chaud de Reaload.

certaines personnes confondent le rechargement à chaud et le redémarrage automatique. Mon module nodejs-autorestart a également une intégration upstart pour activer le démarrage automatique au démarrage. si vous avez une petite application, le redémarrage automatique est correct, mais lorsque vous avez une grande application, le rechargement à chaud est plus approprié. tout simplement parce que le rechargement à chaud est plus rapide.

J'aime aussi mon module d'afflux de nœuds.

Shimon Doodkin
la source
1

Pas nécessaire d'utiliser nodemon ou d'autres outils comme ça. Utilisez simplement les capacités de votre IDE.

Probablement meilleur est IntelliJ WebStorm avec fonction de rechargement à chaud (serveur automatique et reload navigateur) pour Node.js .

lukyer
la source
1

Voici une méthode low tech à utiliser sous Windows. Mettez-le dans un fichier batch appelé serve.bat:

@echo off

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

Maintenant, au lieu d'exécuter à node app.jspartir de votre shell cmd, exécutez serve app.js.

Cela ouvrira une nouvelle fenêtre shell exécutant le serveur. Le fichier de commandes se bloquera (à cause de /wait) jusqu'à ce que vous fermiez la fenêtre du shell, à quel moment le shell cmd d'origine demandera "Terminer la tâche par lots (O / N)?" Si vous répondez "N", le serveur sera relancé.

Chaque fois que vous souhaitez redémarrer le serveur, fermez la fenêtre du serveur et répondez "N" dans le shell cmd.

yo-yo
la source
1

ma structure d'application:

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

installez d'abord reload avec cette commande:

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

puis changez package.json :

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

vous devez maintenant utiliser reload dans votre fichier serveur :

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

et pour le dernier changement, fin de votre réponse envoyez ce script :

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

démarrez maintenant votre application avec ce code:

npm start
کسری کرمی
la source
Cependant, cette approche ne fonctionne pas, contrairement à celles présentées dans npmjs.com/package/reload (pour les applications Express).
Maxie Berkmann
0

Utilisez ceci:

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

Il ne vous reste plus qu'à:

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

Et la configuration sera automatiquement rechargée :)

offlinehacker
la source
Vous avez une version qui ne repose pas sur un framework qui ne fait pas partie de Node?
Adrian
0

loaddir est ma solution pour le chargement rapide d'un répertoire, récursivement.

peut revenir

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

Il a callbackqui sera appelé lorsque le fichier est modifié.

Il gère les situations où les fichiers sont suffisamment volumineux pour watchêtre appelés avant la fin de l'écriture.

Je l'utilise dans des projets depuis environ un an, et j'ai récemment ajouté des promesses.

Aidez-moi à le tester!

https://github.com/danschumann/loaddir

Funkodebat
la source
0

Vous pouvez utiliser le rechargement automatique pour recharger le module sans arrêter le serveur.

installer

npm install auto-reload

exemple

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

Résultat:

{ 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
la source
0

une autre solution simple consiste à utiliser fs.readFile au lieu d'utiliser require, vous pouvez enregistrer un fichier texte contenant un objet json et créer un intervalle sur le serveur pour recharger cet objet.

avantages:

  • pas besoin d'utiliser des bibliothèques externes
  • pertinent pour la production (rechargement du fichier de configuration en cas de changement)
  • facile à mettre en œuvre

les inconvénients:

  • vous ne pouvez pas recharger un module - juste un json contenant des données de valeur-clé
Imri
la source
0

Pour les personnes utilisant Vagrant et PHPStorm, l' observateur de fichiers est une approche plus rapide

  • désactivez la synchronisation immédiate des fichiers afin d'exécuter la commande uniquement lors de l'enregistrement, puis créez une étendue pour les fichiers * .js et les répertoires de travail et ajoutez cette commande

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

où forever.sh est comme

#!/bin/bash

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

Je suis récemment venu à cette question parce que les suspects habituels ne travaillaient pas avec des packages liés. Si vous êtes comme moi et que vous tirez parti du npm linkdéveloppement pour travailler efficacement sur un projet composé de nombreux packages, il est important que les changements qui se produisent dans les dépendances déclenchent également un rechargement.

Après avoir essayé node-mon et pm2, même en suivant leurs instructions pour regarder en plus le dossier node_modules, ils n'ont toujours pas détecté les modifications. Bien qu'il y ait des solutions personnalisées dans les réponses ici, pour quelque chose comme ça, un package séparé est plus propre. J'ai rencontré node-dev aujourd'hui et cela fonctionne parfaitement sans aucune option ni configuration.

Du Readme:

Contrairement à des outils comme superviseur ou nodemon, il ne recherche pas dans le système de fichiers les fichiers à surveiller. Au lieu de cela, il se connecte à la fonction require () de Node pour ne regarder que les fichiers qui ont été réellement requis.

Aaron Storck
la source
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
la source
0

Vous pouvez le faire avec l' actualisation du navigateur . Votre application de nœud redémarre automatiquement, votre page de résultats dans le navigateur est également actualisée automatiquement. L'inconvénient est que vous devez mettre l'extrait de code js sur la page générée. Voici le dépôt pour l'exemple de travail.

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}/` })
    }

});
Jan Pi
la source
0

J'ai essayé pm2 : l'installation est facile et facile à utiliser aussi; le résultat est satisfaisant. Cependant, nous devons nous occuper de l'édition de pm2 que nous voulons. pm 2 runtime est l'édition gratuite, tandis que pm2 plus et pm2 enterprise ne sont pas gratuites.

Quant à Strongloop , mon installation a échoué ou n'était pas terminée, donc je ne pouvais pas l'utiliser.

Lex Soft
la source
-1

De nos jours, le serveur de développement WebPack avec option chaude est utilisé. vous pouvez ajouter un script comme celui-ci dans votre package.json:"hot": "cross-env NODE_ENV=development webpack-dev-server --hot --inline --watch-poll",

et chaque changement dans vos fichiers déclenchera automatiquement une recompilation

eKelvin
la source
2
Cette réponse est fausse par rapport à la question. Webpack est destiné aux applications frontales et le serveur de développement est un serveur Web à part entière. La question faisait référence à une application serveur implémentée dans Node. Il n'a pas besoin d'un serveur Web. C'est déjà un.
DanielKhan