Como recarregar arquivos automaticamente no Node.js?

444

Alguma idéia de como eu poderia implementar um recarregamento automático de arquivos no Node.js. Estou cansado de reiniciar o servidor toda vez que altero um arquivo. Aparentemente, a require()função Node.js. não recarrega os arquivos se eles já tiverem sido solicitados, por isso preciso fazer algo assim:

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 no arquivo app.js eu tenho:

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

Mas isso também não está funcionando - eu recebo um erro na process.compile()declaração dizendo que 'require' não está definido. process.compileestá avaliando o app.js , mas não tem idéia sobre os globais do node.js.

disc0dancer
fonte
4
Você sabe que pode executar esse código em cada solicitação:Object.keys(require.cache).forEach(function(key) { delete require.cache[key]; });
Torre

Respostas:

562

Uma boa alternativa atualizada supervisoré nodemon:

Monitore todas as alterações em seu aplicativo node.js. e reinicie automaticamente o servidor - perfeito para desenvolvimento

Para usar nodemon:

$ npm install nodemon -g
$ nodemon app.js
Marius Butuc
fonte
2
e se você quiser usá-lo em Nitrous.io - $ nodemon -L yourfile.js(explicação completa no coderwall.com/p/aqxl_q )
drzaus
3
Mas, neste caso, ele também reinicia o processo do servidor.
Filipe
@Filipe, você está certo. Eu sou redirecionado para entrar novamente. Desejo que apenas carregue esse módulo modificado específico.
Ar2015 #
7
automatically restart the server - perfect for developmenté muito hipérbole. Recarregar servidor pode significar fazer login em serviços de back-end, o que leva muito tempo no meu caso. "Perfeito para o desenvolvimento" seria algo como classes de recarga a quente enquanto o processo está em execução na memória sem perder o estado do que o android studio faz quando você altera o código-fonte.
Nurettin
2
use npm install [--save-dev | -D] nodemonpara limitar a instalação ao escopo do projeto.
themefield 22/07/19
312

supervisor de nó é impressionante

uso para reiniciar ao salvar:

supervisor de instalação do npm -g
supervisor app.js

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

Anup Bishnoi
fonte
3
npm install -g supervisor. Ele deve ser instalado globalmente.
precisa saber é o seguinte
No OSX 10.2.8 i teve que executá-lo com sudo
Timopheym
2
Tive que executá-lo desta maneira no Windows:"C:\Program Files\nodejs\node.exe" C:\Users\Mark\AppData\Roaming\npm\node_modules\supervisor\lib\cli-wrapper.js app.js
mpen 14/01
1
sem -g ou sudo na raiz app: npm install supervisor, node node_modules/supervisor/lib/cli-wrapper.js app.js(eu tenho uma instalação não-raiz do Node)
h-Kippo
1
@ Marcos Este nó meios não está na suaPATH
Blaise
87

eu encontrei uma maneira simples:

delete require.cache['/home/shimin/test2.js']
Inshua
fonte
7
Isso é ótimo se você deseja recarregar bibliotecas externas sem reiniciar o aplicativo - no meu caso, um bot de IRC.
Michelle Tilley
Isto e excelente! Tão simples e funciona tão bem. Sempre que uma solicitação é recebida, eu desachei um monte de arquivos que não mantêm o estado.
Vaughan
16
delete require.cache[require.resolve('./mymodule.js')]; negócio resolve com caminhos reais
Eduardo
Isso é seguro para fazer ou considerado "má prática" ou "apenas desenvolvimento"?
21416 jocull
2
@jocull Eu não acho que é seguro, uma vez que pode recriar classes e funções ou qualquer exportações, resultando em diferentes referências quando se compara com===
Kroltan
20

Se alguém ainda chega a essa pergunta e quer resolvê-la usando apenas os módulos padrão, fiz um exemplo simples:

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 exemplo é apenas para um arquivo (server.js), mas pode ser adaptado a vários arquivos usando uma matriz de arquivos, um loop for para obter todos os nomes de arquivos ou assistindo a um diretório:

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 foi criado para a API Node.js 0.8, não está adaptado para algumas necessidades específicas, mas funcionará em alguns aplicativos simples.

UPDATE: Esta funcionalidade é implementada no meu módulo simpleR , repositório GitHub

micnic
fonte
1
Esta é uma solução excelente e simples. Eu apenas o usei para um bot que deveria se atualizar do git quando solicitado por um moderador. O problema era que, uma vez dentro do aplicativo, você não pode se reiniciar. No entanto, posso usar seu método para gerar uma instância do bot e assistir a um arquivo de pontos. O bot então se atualiza, toca o arquivo de pontos e será reiniciado automaticamente pelo iniciador. Impressionante!
Fred
@Fred Fico feliz em ouvir isso :) Vou implementar esta solução em um módulo, em breve, eu acho, eu tenho mais algumas idéias de como expandir sua funcionalidade
micnic
Se o arquivo watchnão for necessário, é possível recarregar sem fsouvir um sinal diferente.
Vladimir Vukanac 18/01/19
18

nodemon surgiu primeiro em uma pesquisa no google, e parece fazer o truque:

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

Há um Node-Supervisor que você pode instalar

npm install supervisor

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

Richard Metzler
fonte
2
É mais sobre reiniciar o servidor se ele travar. O supervisor de nó também reinicia todo o processo quando os arquivos monitorados foram alterados. Não é uma recarga a quente no sentido estrito.
precisa saber é
Embora não seja realmente um carregamento a quente, essa ferramenta é realmente útil se você deseja que o código seja carregado automaticamente durante o desenvolvimento, para que você não precise reiniciar o nó na linha de comando após cada alteração.
Derek Dahmer
7

Edit: Minha resposta é obsoleta. O Node.js é uma tecnologia que muda muito rapidamente.

Também me perguntei sobre recarregar módulos. Modifiquei o node.js e publiquei a fonte no Github em nalply / node . A única diferença é a função require. Ele tem um segundo argumento opcional reload.

require(url, reload)

Para recarregar app.jsno diretório atual, use

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

Escreva algo como isto e você terá o recarregamento automático :

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

O único problema que vejo é a variável module, mas estou trabalhando nisso agora.

nalply
fonte
7

nodemoné ótimo. Acabei de adicionar mais parâmetros para opções de depuração e observação.

package.json

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

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

Enquanto que:

--watch serverReinicie o aplicativo ao mudar .js, .mjs, .coffee, .litcoffee, e .jsonarquivos na serverpasta (incluído subpastas).

--inspect Ativar depuração remota.

./server/server.js O ponto de entrada.

Em seguida, adicione a seguinte configuração em launch.json(Código VS) e comece a depurar a qualquer momento.

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

Observe que é melhor instalar nodemoncomo dependência de desenvolvimento do projeto. Para que os membros da sua equipe não precisem instalá-lo ou lembre-se dos argumentos de comando, eles apenas npm run devcomeçam a invadir.

Veja mais em nodemondocumentos: https://github.com/remy/nodemon#monitoring-multiple-directories

Ninh Pham
fonte
Globbing não é suportado para versões recentes do nodemon (1.19.0 pelo menos). Simplesmente use nodemon --watch server --inspect ./server/server.js.
Alex
Obrigado @Alex pela sua informação. Atualizado a resposta.
Ninh Pham
5

Houve um tópico recente sobre esse assunto na lista de discussão node.js. A resposta curta é não, atualmente não é possível recarregar automaticamente os arquivos necessários, mas várias pessoas desenvolveram patches que adicionam esse recurso.

Xavi
fonte
1
+1 Sim. Eu participei da discussão. Eu admiti que minha solução é muito simples. Funciona apenas se o próprio módulo quente não exigir mais módulos. A solução Felix é mais bem pensada, mas é debatida se a auto- recarga realmente pertence ao núcleo.
N
5

ainda outra solução para esse problema está usando para sempre

Outro recurso útil do Forever é que ele pode, opcionalmente, reiniciar seu aplicativo quando qualquer arquivo de origem for alterado. Isso evita que você precise reiniciar manualmente sempre que adicionar um recurso ou corrigir um bug. Para iniciar o Forever nesse modo, use o sinalizador -w:

forever -w start server.js
Teoman shipahi
fonte
Estranhamente com a sinalização -w, meu aplicativo express.js não usa CSS.
Costa
5

O node-dev funciona muito bem. npminstall node-dev

Ele também fornece uma notificação na área de trabalho quando o servidor é recarregado e fornece êxito ou erros na mensagem.

inicie seu aplicativo na linha de comando com:

node-dev app.js

l3o
fonte
3

Aqui está uma postagem de blog sobre o Hot Reloading for Node. Ele fornece uma ramificação do nó do github que você pode usar para substituir sua instalação do nó e ativar o recarregamento a quente.

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

Agora, sempre que você modificar myRequestHandler.js, o código acima notará e substituirá o requestHandler local pelo novo código. Quaisquer pedidos existentes continuarão a usar o código antigo, enquanto quaisquer novos pedidos recebidos usarão o novo código. Tudo sem desligar o servidor, rejeitar solicitações, interromper prematuramente quaisquer solicitações ou até mesmo confiar em um balanceador de carga inteligente.

Chetan
fonte
A única coisa com esta solução é que ela é uma bifurcação de uma versão mais antiga do Node, portanto ela precisará ser ajustada e mesclada com a versão mais recente antes de usar (a menos que você não se importe em usar uma versão mais antiga do Node).
Chetan
3

Estou trabalhando para criar uma "coisa" de nó bastante pequeno que seja capaz de carregar / descarregar módulos à vontade (por exemplo, você poderá reiniciar parte do seu aplicativo sem desativar o aplicativo inteiro). Estou incorporando um gerenciamento de dependências (muito estúpido), de modo que, se você quiser parar um módulo, todos os módulos que dependem disso também serão parados.

Até agora tudo bem, mas então me deparei com a questão de como recarregar um módulo. Aparentemente, pode-se remover o módulo do cache "require" e concluir o trabalho. Desde que eu não estou interessado em alterar diretamente o código-fonte nó, eu vim com uma muito hacky-hack que é: procure no rastreamento de pilha a última chamada para a "exigir" função, pegue uma referência ao campo que é "cache" e..bem, exclua a referência para o nó:

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

Ainda mais fácil, na verdade:

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

Aparentemente, isso funciona muito bem. Não tenho absolutamente nenhuma idéia do que esses argumentos ["1"] significam, mas está fazendo seu trabalho. Eu acredito que o pessoal do nó implementará um recurso de recarga algum dia, então acho que por enquanto essa solução também é aceitável. (btw. minha "coisa" estará aqui: https://github.com/cheng81/wirez , vá lá em algumas semanas e você deverá ver do que estou falando)

cheng81
fonte
..claro que não é tão simples. Isso funciona apenas se houver uma chamada para exigir na pilha de chamadas. Oh, bem, fácil hack em cima de um hack: escreva essas coisas em um script temporário e exija-as em tempo de execução. Fez isso, ele works..and ainda limpar-se a partir do cache
cheng81
E, na verdade, era mais fácil: delete (require.cache [moduleFullpathAndExt]) #
cheng81
Na verdade, os módulos Node.js são agrupados em uma função anônima, que é como o encapsulamento do módulo é feito. Cada módulo realmente se parece function (module, require) { /* your code */ }. Quando você leva isso em consideração, arguments[1]aponta para require. E o loop while está lá para situações em que você chama isso de dentro de outra função em um módulo (ele simplesmente sobe na hierarquia de funções e verifica os valores dos argumentos passados ​​para cada).
JK
3

Você pode usar o nodemon do NPM . E se você estiver usando o gerador Express, poderá usar este comando dentro da pasta do projeto:

nodemon npm start

ou usando o modo de depuração

DEBUG=yourapp:* nodemon npm start

você também pode executar diretamente

nodemon your-app-file.js

Espero que esta ajuda.

azwar_akbar
fonte
1

solução em: http://github.com/shimondoodkin/node-hot-reload

observe que você deve cuidar das referências usadas.

isso significa que se você fez: var x = require ('foo'); y = x; z = x.bar; e quente recarregado.

isso significa que você deve substituir as referências armazenadas em x, ye z. na função de retorno de chamada reaload quente.

algumas pessoas confundem recarga a quente com reinicialização automática, o módulo nodejs-autorestart também possui integração inicial para permitir o início automático na inicialização. se você tiver um pequeno aplicativo, a reinicialização automática é boa, mas quando você tem um aplicativo grande, a recarga a quente é mais adequada. simplesmente porque a recarga a quente é mais rápida.

Também gosto do meu módulo de entrada de nós.

Shimon Doodkin
fonte
1

Não é necessário usar nodemon ou outras ferramentas como essa. Basta usar os recursos do seu IDE.

Provavelmente melhor é IntelliJ WebStorm com característica de recarga quente (servidor automático e recarga browser) para node.js .

lukyer
fonte
1

Aqui está um método de baixa tecnologia para uso no Windows. Coloque isso em um arquivo em lotes chamado serve.bat:

@echo off

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

Agora, em vez de executar node app.jsno seu cmd shell, execute serve app.js.

Isso abrirá uma nova janela do shell executando o servidor. O arquivo em lote será bloqueado (por causa do /wait) até que você feche a janela do shell; nesse momento, o cmd original perguntará "Terminar trabalho em lotes (S / N)?" Se você responder "N", o servidor será reiniciado.

Sempre que desejar reiniciar o servidor, feche a janela do servidor e responda "N" no shell do cmd.

yoyo
fonte
1

minha estrutura de aplicativos:

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

primeiro instale o recarregamento com este comando:

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

altere package.json :

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

agora você deve usar recarregar no arquivo do 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);

e para a última alteração, final da sua resposta envie este script :

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

agora inicie seu aplicativo com este código:

npm start
کسری کرمی
fonte
Essa abordagem não funciona, no entanto, as apresentadas em npmjs.com/package/reload (para aplicativos Express) funcionam.
Maxie Berkmann 29/03
0

Usa isto:

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

Tudo o que você precisa fazer agora é:

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

E a configuração será recarregada automaticamente :)

offlinehacker
fonte
Tem uma versão que não depende de uma estrutura que não faz parte do Node?
Adrian
0

loaddir é a minha solução para carregamento rápido de um diretório, recursivamente.

pode retornar

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

Tem o callbackque será chamado quando o arquivo for alterado.

Ele lida com situações em que os arquivos são grandes o suficiente para serem watchchamados antes de terminar a gravação.

Uso-o em projetos há um ano ou mais e recentemente acrescentei promessas a ele.

Ajude-me a testá-lo!

https://github.com/danschumann/loaddir

Funkodebat
fonte
0

Você pode usar o recarregamento automático para recarregar o módulo sem desligar o servidor.

instalar

npm install auto-reload

exemplo

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

outra solução simples é usar fs.readFile em vez de exigir que você possa salvar um arquivo de texto contendo um objeto json e criar um intervalo no servidor para recarregar esse objeto.

profissionais:

  • não há necessidade de usar bibliotecas externas
  • relevante para a produção (recarregando o arquivo de configuração na mudança)
  • fácil de implementar

contras:

  • você não pode recarregar um módulo - apenas um json contendo dados de valor-chave
Imri
fonte
0

Para pessoas que usam o Vagrant e o PHPStorm, o observador de arquivos é uma abordagem mais rápida

  • desative a sincronização imediata dos arquivos para que você execute o comando apenas em save, crie um escopo para os arquivos * .js e diretórios de trabalho e adicione este comando

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

onde forever.sh é como

#!/bin/bash

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

Recentemente, cheguei a essa pergunta porque os suspeitos comuns não estavam trabalhando com pacotes vinculados. Se você é como eu e está aproveitando npm linkdurante o desenvolvimento para trabalhar efetivamente em um projeto que é composto por muitos pacotes, é importante que as alterações que ocorrem nas dependências disparem uma recarga também.

Depois de tentar o node-mon e o pm2, mesmo seguindo as instruções para assistir adicionalmente à pasta node_modules, eles ainda não capturaram as alterações. Embora existam algumas soluções personalizadas nas respostas aqui, para algo assim, um pacote separado é mais limpo. Encontrei o node-dev hoje e funciona perfeitamente sem opções ou configurações.

No Leiame:

Ao contrário de ferramentas como supervisor ou nodemon, ele não verifica o sistema de arquivos em busca de arquivos a serem observados. Em vez disso, ele se conecta à função require () do Node para observar apenas os arquivos que foram realmente necessários.

Aaron Storck
fonte
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
fonte
0

Você pode fazer isso com a atualização do navegador . Seu aplicativo do nó é reiniciado automaticamente, sua página de resultados no navegador também é atualizada automaticamente. A desvantagem é que você deve colocar o snippet js na página gerada. Aqui está o repo para o exemplo de trabalho.

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

Eu tentei o pm2 : a instalação também é fácil e fácil de usar; o resultado é satisfatório. No entanto, precisamos cuidar de qual edição do pm2 queremos. O pm 2 runtime é a edição gratuita, enquanto o pm2 plus e o pm2 enterprise não são gratuitos.

Quanto ao Strongloop , minha instalação falhou ou não foi concluída, portanto não pude usá-lo.

Lex Soft
fonte
-1

Atualmente, o servidor de desenvolvimento WebPack com opção hot é usado. você pode adicionar um script como este em seu package.json:"hot": "cross-env NODE_ENV=development webpack-dev-server --hot --inline --watch-poll",

e todas as alterações em seus arquivos acionarão uma recompilação automaticamente

eKelvin
fonte
2
Esta resposta está errada na pergunta. O Webpack é para aplicativos de front-end e o servidor de desenvolvimento é um servidor da web por conta própria. A questão estava se referindo a um aplicativo de servidor implementado no Nó. Não precisa de um servidor web. Já é um.
precisa saber é o seguinte