¿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.


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

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


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

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


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

8

Hay Node-Supervisor que puede instalar por

npm install supervisor

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


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.


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


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.


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

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


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.


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)


..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.


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.


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 .


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.


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

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


¿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


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

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

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

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.


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

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

});

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.


-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


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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.