¿Cómo recargar automáticamente los archivos en Node.js?

444

¿Alguna idea sobre cómo podría implementar una recarga automática de archivos en Node.js? Estoy cansado de reiniciar el servidor cada vez que cambio un archivo. Aparentemente, la require()función de Node.js no vuelve a cargar archivos si ya se han requerido, por lo que necesito hacer algo como esto:

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

Y en el archivo app.js tengo:

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

Pero esto tampoco funciona: recibo un error en la process.compile()declaración que dice que 'requerir' no está definido. process.compileestá evaluando el app.js , pero no tiene idea sobre los nodos globales de node.js.

disc0dancer
fuente
44
Usted sabe que puede ejecutar este código en cada solicitud:Object.keys(require.cache).forEach(function(key) { delete require.cache[key]; });
Torre

Respuestas:

562

Una buena alternativa actualizada supervisores nodemon:

Monitoree cualquier cambio en su aplicación node.js y reinicie automáticamente el servidor, perfecto para el desarrollo

Para utilizar nodemon:

$ npm install nodemon -g
$ nodemon app.js
Marius Butuc
fuente
2
y si quieres usarlo en Nitrous.io - $ nodemon -L yourfile.js(explicación completa en coderwall.com/p/aqxl_q )
drzaus
3
Pero en este caso, también reinicia el proceso del servidor.
Filipe
@Filipe, tienes razón. Soy redirigido para iniciar sesión nuevamente. Desearía que solo cargara ese módulo modificado específico.
ar2015
77
automatically restart the server - perfect for developmentEs demasiada hipérbole. Recargar el servidor podría significar iniciar sesión en los servicios de backend, lo que en mi caso lleva mucho tiempo. "Perfecto para el desarrollo" sería algo así como recargar en caliente las clases mientras el proceso se ejecuta en la memoria sin perder el estado al igual que lo que hace Android Studio cuando cambia el código fuente.
nurettin
2
use npm install [--save-dev | -D] nodemonpara limitar la instalación al alcance del proyecto.
themefield
312

supervisor de nodo es increíble

uso para reiniciar al guardar:

supervisor de instalación de npm -g
supervisor app.js

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

Anup Bishnoi
fuente
3
npm install -g supervisor. Debe instalarse a nivel mundial.
Kamal Reddy
En OSx 10.2.8 tuve que ejecutarlo con sudo
Timopheym
2
Tuve que ejecutarlo así en Windows:"C:\Program Files\nodejs\node.exe" C:\Users\Mark\AppData\Roaming\npm\node_modules\supervisor\lib\cli-wrapper.js app.js
mpen
1
sin -g o sudo a raíz de aplicación: npm install supervisor, node node_modules/supervisor/lib/cli-wrapper.js app.js(tengo una instalación no root de Node)
h-kippo
1
@ Mark Esto significa que el nodo no está en tuPATH
Blaise
87

Encontré una manera simple:

delete require.cache['/home/shimin/test2.js']
Inshua
fuente
77
Esto es genial si desea volver a cargar bibliotecas externas sin reiniciar la aplicación, en mi caso, un bot IRC.
Michelle Tilley
¡Esto es excelente! Tan simple y funciona muy bien. Cada vez que llega una solicitud, simplemente elimino un montón de archivos que no tienen estado.
Vaughan
16
delete require.cache[require.resolve('./mymodule.js')]; resolver acuerdo con caminos reales
Eduardo
¿Es seguro hacerlo o se considera "mala práctica" o "solo desarrollo"?
jocull
2
@jocull no creo que es seguro, ya que puede volver a crear clases y funciones o lo que las exportaciones, lo que resulta en diferentes referencias al comparar con===
Kroltan
20

Si alguien aún llega a esta pregunta y quiere resolverla usando solo los módulos estándar, hice un ejemplo 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();
});

Este ejemplo es solo para un archivo (server.js), pero se puede adaptar a múltiples archivos usando una matriz de archivos, un bucle for para obtener todos los nombres de archivos o mirando un directorio:

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

Este código se creó para la API Node.js 0.8, no está adaptado para algunas necesidades específicas, pero funcionará en algunas aplicaciones simples.

ACTUALIZACIÓN: Este funcional se implementa en mi módulo simpleR , repositorio de GitHub

micnic
fuente
1
Esta es una excelente y simple solución. Solo lo usé para un bot que se suponía que debía actualizarse desde git cuando un moderador lo indicara. El problema fue que una vez que estás dentro de la aplicación no puedes reiniciarte. Sin embargo, puedo usar su método para generar una instancia del bot y ver un archivo de puntos. El bot luego se actualiza, toca el archivo de puntos y el iniciador lo reiniciará automáticamente. ¡Increíble!
Fred
@ Fred me alegra escuchar esto :) Implementaré esta solución en un módulo, pronto supongo, tengo algunas ideas más sobre cómo expandir su funcionalidad
micnic
Si archivo watch no se necesita el , la recarga se puede realizar sin fsescuchar una señal diferente.
Vladimir Vukanac
18

nodemon apareció primero en una búsqueda de google, y parece que funciona:

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

Hay Node-Supervisor que puede instalar por

npm install supervisor

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

Richard Metzler
fuente
2
Se trata más de reiniciar el servidor si falla. El supervisor de nodo también reinicia todo el proceso cuando se han cambiado los archivos observados. No es recarga en caliente en sentido estricto.
finalmente
Aunque en realidad no es de carga en caliente, esta herramienta es realmente útil si solo desea que el código se vuelva a cargar automáticamente durante el desarrollo para que no tenga que reiniciar el nodo en la línea de comando después de cada cambio.
Derek Dahmer
7

Editar: mi respuesta es obsoleta. Node.js es una tecnología que cambia muy rápido.

También me preguntaba sobre la recarga de módulos. Modifiqué node.js y publiqué la fuente en Github en nalply / node . La única diferencia es la función require. Tiene un segundo argumento opcional reload.

require(url, reload)

Para recargar app.jsen el directorio actual use

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

Escribe algo como esto, y tienes auto- recarga:

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

El único problema que veo es la variable module, pero ahora estoy trabajando en ello.

finalmente
fuente
7

nodemones genial Solo agrego más parámetros para depurar y ver las opciones.

package.json

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

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

Mientras:

--watch serverReinicia la aplicación cuando se cambia .js, .mjs, .coffee, .litcoffee, y .jsonlos archivos de la servercarpeta (incluidas las subcarpetas).

--inspect Habilitar depuración remota.

./server/server.js El punto de entrada.

Luego agregue la siguiente configuración a launch.json(Código VS) y comience a depurar en cualquier momento.

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

Tenga en cuenta que es mejor instalar nodemoncomo dependencia de desarrollo del proyecto. Por lo tanto, los miembros de su equipo no necesitan instalarlo o recordar los argumentos del comando, simplemente npm run devcomienzan a hackear.

Ver más en nodemondocumentos: https://github.com/remy/nodemon#monitoring-multiple-directories

Ninh Pham
fuente
Globbing no es compatible con versiones recientes de nodemon (1.19.0 al menos). Simplemente use nodemon --watch server --inspect ./server/server.js en su lugar.
Alex
Gracias @Alex por tu información. Se actualizó la respuesta.
Ninh Pham
5

Hubo un hilo reciente sobre este tema en la lista de correo de node.js. La respuesta corta es no, actualmente no es posible recargar automáticamente los archivos requeridos, pero varias personas han desarrollado parches que agregan esta característica.

Xavi
fuente
1
+1 sí. Participé en la discusión. Admití que mi solución es demasiado simple. Solo funciona si el módulo dinámico en sí no requiere más módulos. La solución de Felix está mejor pensada, pero se debate si la recarga automática realmente pertenece al núcleo.
nalply
5

otra solución para este problema es usar para siempre

Otra capacidad útil de Forever es que, opcionalmente, puede reiniciar su aplicación cuando cualquier archivo fuente ha cambiado. Esto le libera de tener que reiniciar manualmente cada vez que agrega una función o corrige un error. Para iniciar Forever en este modo, use la bandera -w:

forever -w start server.js
Teoman shipahi
fuente
Extrañamente con la bandera -w, mi aplicación express.js no usa CSS.
Costa
5

node-dev funciona muy bien. npminstall node-dev

Incluso da una notificación de escritorio cuando el servidor se vuelve a cargar y dará éxito o errores en el mensaje.

Inicie su aplicación en la línea de comandos con:

node-dev app.js

l3o
fuente
3

Aquí hay una publicación de blog sobre Hot Reloading for Node. Proporciona una rama de nodo github que puede usar para reemplazar su instalación de Nodo para habilitar la Recarga en Caliente.

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

Ahora, cada vez que modifique myRequestHandler.js, el código anterior notará y reemplazará el requestHandler local con el nuevo código. Cualquier solicitud existente continuará usando el código anterior, mientras que cualquier solicitud entrante nueva usará el nuevo código. Todo sin apagar el servidor, rechazar cualquier solicitud, eliminar prematuramente cualquier solicitud o incluso confiar en un equilibrador de carga inteligente.

Chetan
fuente
Lo único con esta solución es que es una bifurcación de una versión anterior de Node, por lo que tendrá que ser modificada y fusionada con la última versión antes de usarla (a menos que no le importe usar una versión anterior de Node).
Chetan
3

Estoy trabajando en hacer una "cosa" de nodo bastante pequeña que sea capaz de cargar / descargar módulos a voluntad (es decir, podría reiniciar parte de su aplicación sin cerrar toda la aplicación). Estoy incorporando una gestión de dependencia (muy estúpida), de modo que si desea detener un módulo, también se detendrán todos los módulos que dependen de eso.

Hasta ahora todo bien, pero luego me topé con el problema de cómo volver a cargar un módulo. Aparentemente, uno podría simplemente eliminar el módulo de la caché "require" y hacer el trabajo. Como no estoy interesado en cambiar directamente el código fuente del nodo, se me ocurrió un truco muy hacky: buscar en la pila rastrear la última llamada a la función "require", tomar una referencia a su campo "cache" y ... bueno, elimine la referencia 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 ] )

Aún más fácil, en realidad:

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

Aparentemente, esto funciona bien. No tengo ni idea de lo que significan esos argumentos ["1"], pero está haciendo su trabajo. Creo que los nodos implementarán una instalación de recarga algún día, así que supongo que por ahora esta solución también es aceptable. (por cierto, mi "cosa" estará aquí: https://github.com/cheng81/wirez , ve allí en un par de semanas y deberías ver de qué estoy hablando)

cheng81
fuente
..por supuesto no es tan simple. Eso solo funciona si hay una llamada que se requiere en la pila de llamadas. Oh, bueno, hack fácil sobre un hack: escribe esas cosas en un script temporal, y requiérelas en tiempo de ejecución. Lo hizo, funciona ... e incluso se limpió a sí mismo del caché
cheng81
Y en realidad fue más fácil: eliminar (require.cache [moduleFullpathAndExt])
cheng81
Los módulos Node.js en realidad están envueltos en una función anónima que es cómo se realiza la encapsulación del módulo. Cada módulo realmente se parece function (module, require) { /* your code */ }. Cuando tiene esto en cuenta, arguments[1]apunta a require. Y el ciclo while está ahí para situaciones en las que se llama desde otra función en un módulo (simplemente sube la jerarquía de funciones y verifica los valores de argumento pasados ​​a cada uno).
JK
3

Puede usar nodemon de NPM . Y si está utilizando el generador Express, puede usar este comando dentro de la carpeta de su proyecto:

nodemon npm start

o usando el modo de depuración

DEBUG=yourapp:* nodemon npm start

también puedes correr directamente

nodemon your-app-file.js

Espero que esto ayude.

azwar_akbar
fuente
1

solución en: http://github.com/shimondoodkin/node-hot-reload

Tenga en cuenta que debe tener cuidado usted mismo de las referencias utilizadas.

eso significa que si lo hiciste: var x = require ('foo'); y = x; z = x.bar; y caliente lo volvió a cargar.

significa que debe reemplazar las referencias almacenadas en x, y y z. en la función de reaload callback caliente.

Algunas personas confunden la recarga en caliente con el reinicio automático. si tiene una aplicación pequeña, el reinicio automático está bien, pero cuando tiene una aplicación grande, la recarga en caliente es más adecuada. simplemente porque la recarga en caliente es más rápida.

También me gusta mi módulo de entrada de nodo.

Shimon Doodkin
fuente
1

No es necesario usar nodemon u otras herramientas como esa. Simplemente use las capacidades de su IDE.

Probablemente es mejor IntelliJ WebStorm con componente de renovación caliente (servidor de recarga automática y navegador) para Node.js .

lukyer
fuente
1

Aquí hay un método de baja tecnología para usar en Windows. Ponga esto en un archivo por lotes llamado serve.bat:

@echo off

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

Ahora, en lugar de ejecutar node app.jsdesde su shell de cmd, ejecute serve app.js.

Esto abrirá una nueva ventana de shell que ejecuta el servidor. El archivo por lotes se bloqueará (debido a /wait) hasta que cierre la ventana del shell, en cuyo momento el shell de cmd original preguntará "¿Terminar el trabajo por lotes (S / N)?" Si responde "N", el servidor se reiniciará.

Cada vez que desee reiniciar el servidor, cierre la ventana del servidor y responda "N" en el shell de cmd.

yoyó
fuente
1

la estructura de mi aplicación

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

primero instale reload con este comando:

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

luego cambie package.json :

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

ahora debe usar reload en su archivo de servidor :

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

y para el último cambio, al final de su respuesta envíe este script :

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

ahora inicie su aplicación con este código:

npm start
کسری کرمی
fuente
Sin embargo, este enfoque no funciona, los que aparecen en npmjs.com/package/reload (para aplicaciones Express) sí.
Maxie Berkmann
0

Utilizar este:

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

Todo lo que tienes que hacer ahora es:

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

Y la configuración se volverá a cargar automáticamente :)

desconectado
fuente
¿Tienes una versión que no se basa en un marco que no es parte de Node?
Adrian el
0

loaddir es mi solución para la carga rápida de un directorio, de forma recursiva.

puede volver

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

Tiene callbackcuál será llamado cuando se cambie el archivo.

Maneja situaciones donde los archivos son lo suficientemente grandes como para ser watchllamados antes de que terminen de escribir.

Lo he estado usando en proyectos durante un año más o menos, y recientemente le agregué promesas.

¡Ayúdame a luchar, pruébalo!

https://github.com/danschumann/loaddir

Funkodebat
fuente
0

Puede usar la recarga automática para volver a cargar el módulo sin apagar el servidor.

Instalar en pc

npm install auto-reload

ejemplo

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

Resultado:

{ 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
fuente
0

Otra solución simple es usar fs.readFile en lugar de usar require , puede guardar un archivo de texto que contenga un objeto json y crear un intervalo en el servidor para recargar este objeto.

pros:

  • no es necesario usar libs externas
  • relevante para la producción (recarga del archivo de configuración en el cambio)
  • fácil de implementar

contras:

  • no puede volver a cargar un módulo, solo un json que contiene datos clave-valor
Imri
fuente
0

Para las personas que usan Vagrant y PHPStorm, el observador de archivos es un enfoque más rápido

  • deshabilite la sincronización inmediata de los archivos para que ejecute el comando solo en guardar y luego cree un ámbito para los archivos * .js y directorios de trabajo y agregue este comando

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

donde forever.sh es como

#!/bin/bash

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

Recientemente llegué a esta pregunta porque los sospechosos habituales no estaban trabajando con paquetes vinculados. Si eres como yo y aprovechas npm linkdurante el desarrollo para trabajar eficazmente en un proyecto que se compone de muchos paquetes, es importante que los cambios que ocurren en las dependencias también desencadenen una recarga.

Después de haber probado node-mon y pm2, incluso siguiendo sus instrucciones para ver adicionalmente la carpeta node_modules, aún no recogieron los cambios. Aunque hay algunas soluciones personalizadas en las respuestas aquí, para algo como esto, un paquete separado es más limpio. Me encontré con node-dev hoy y funciona perfectamente sin ninguna opción o configuración.

Del Léame:

A diferencia de herramientas como supervisor o nodemon, no escanea el sistema de archivos en busca de archivos para ver. En su lugar, se conecta a la función require () de Node para ver solo los archivos que realmente se han requerido.

Aaron Storck
fuente
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;
};
BotellaLiu
fuente
0

Puede hacerlo con la actualización del navegador . Su aplicación de nodo se reinicia automáticamente, su página de resultados en el navegador también se actualiza automáticamente. Lo malo es que tienes que poner el fragmento js en la página generada. Aquí está el repositorio para el ejemplo de trabajo.

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
fuente
0

He intentado pm2 : la instalación es fácil y fácil de usar también; El resultado es satisfactorio. Sin embargo, tenemos que ocuparnos de la edición de pm2 que queremos. pm 2 runtime es la edición gratuita, mientras que pm2 plus y pm2 enterprise no son gratuitas.

En cuanto a Strongloop , mi instalación falló o no se completó, por lo que no pude usarla.

Lex Soft
fuente
-1

Hoy en día se usa el servidor de desarrollo WebPack con la opción hot. puedes agregar un script como este en tu package.json:"hot": "cross-env NODE_ENV=development webpack-dev-server --hot --inline --watch-poll",

y cada cambio en sus archivos desencadenará una recompilación automáticamente

eKelvin
fuente
2
Esta respuesta es incorrecta con la pregunta. Webpack es para aplicaciones frontend y el servidor de desarrollo es un servidor web por sí solo. La pregunta se refería a una aplicación de servidor implementada en Node. No necesita un servidor web. Ya es uno.
DanielKhan