如何在Node.js中自动重新加载文件?


443

关于如何在Node.js中实现文件自动重装的任何想法?每次更改文件时,我都无法重新启动服务器。显然,Node.js的require()功能不会重新加载文件(如果已经需要),因此我需要执行以下操作:

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

app.js文件中,我有:

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

但这也不起作用-我在process.compile()声明“ require”未定义的语句中遇到错误。process.compile正在逃避app.js,但不了解node.js全局变量。


4
您知道您可以在每个请求上运行此代码:Object.keys(require.cache).forEach(function(key) { delete require.cache[key]; });

Answers:


560

一个很好的,最新的替代方法supervisornodemon

监视node.js应用程序中的任何更改并自动重启服务器-非常适合开发

使用方法nodemon

$ npm install nodemon -g
$ nodemon app.js

2
如果你想用它在Nitrous.io - $ nodemon -L yourfile.js(全解释coderwall.com/p/aqxl_q
drzaus

3
但是在这种情况下,它也会重新启动服务器进程。
菲利普(Filipe)

@Filipe,你是对的。我被重定向到再次登录。我希望它仅加载该特定的修改后的模块。
ar2015年

7
automatically restart the server - perfect for development太夸张了。重新加载服务器可能意味着登录后端服务,这对我而言确实需要很长时间。“完美的开发”就像是在进程在内存中运行时热重载类,而不会丢失状态,就像在更改源代码时android studio所做的那样。
nurettin

2
用于npm install [--save-dev | -D] nodemon将安装限制为项目范围。
themefield '19

312

节点主管很棒

在保存时重新启动的用法:

npm安装主管-g
主管app.js

由伊萨克- http://github.com/isaacs/node-supervisor


3
npm install -g主管。它应该全局安装。
卡马尔·雷迪

在OSx 10.2.8上,我必须使用sudo运行它
Timopheym

2
不得不在Windows下这样运行:"C:\Program Files\nodejs\node.exe" C:\Users\Mark\AppData\Roaming\npm\node_modules\supervisor\lib\cli-wrapper.js app.js
mpen

1
在应用程序根目录下没有-g或sudo:npm install supervisornode node_modules/supervisor/lib/cli-wrapper.js app.js(我有Node的非根目录安装)
h-kippo

1
@Mark这表示节点不在您的位置PATH
Blaise

87

我找到了一种简单的方法:

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

7
如果您要重新加载外部库而无需重新启动应用程序,那么这很好。
Michelle Tilley

太好了!非常简单,效果很好。每当有请求进入时,我都会取消缓存一堆不保持状态的文件。
旺市

16
delete require.cache[require.resolve('./mymodule.js')]; 决心应对现实路径
爱德华

这是安全的做法还是被认为是“不良做法”或“仅发展”?
jocull

2
@jocull我认为这并不安全,因为它可能会重新创建类和函数或进行任何导出,从而与===
Kroltan

20

如果仍然有人要解决这个问题,并且只想使用标准模块来解决,我举了一个简单的例子:

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

本示例仅适用于一个文件(server.js),但可以使用文件数组,用于获取所有文件名的for循环或通过查看目录将其改编为多个文件:

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

该代码是针对Node.js 0.8 API编写的,不适用于某些特定需求,但可以在某些简单应用中使用。

更新:此功能在我的模块simpleRGitHub repo中实现


1
这是一个很棒且简单的解决方案。我只是将它用于一个机器人,当主持人告知时,该机器人应该从git更新自身。问题在于,一旦进入应用程序,就无法重新启动自己。但是,我可以使用您的方法来生成bot实例并观察dotfile。然后,机器人会自我更新,触摸点文件,然后启动器会自动将其重新启动。太棒了!
Fred

@Fred我很高兴听到这个消息:)我将在一个模块中实现该解决方案,我想很快,我对如何扩展其功能还有更多的想法
micnic 2013年

如果watch不需要文件,则可以fs通过侦听不同的信号而无需进行重新加载。
Vladimir Vukanac

18

nodemon首先出现在Google搜索中,并且似乎可以解决这个问题:

npm install nodemon -g
cd whatever_dir_holds_my_app
nodemon app.js

8

您可以通过安装Node-Supervisor

npm install supervisor

参见http://github.com/isaacs/node-supervisor


2
如果服务器崩溃,则更多的是重新启动服务器。当监视的文件已更改时,node-supervisor也会重新启动整个过程。从严格意义上讲,它不是热装。
2010年

尽管并不是真正的热加载,但是如果您只是想在开发过程中自动重新加载代码,那么不必每次更改后都必须在命令行中重新启动节点,那么此工具将非常有用。
德里克·达默

7

编辑:我的答案已过时。Node.js是一项快速变化的技术。

我也想知道重新加载模块。我修改了node.js,并在nathly / node的 Github上发布了源代码。唯一的区别是功能require。它有一个可选的第二个参数reload

require(url, reload)

要重新加载app.js当前目录,请使用

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

像这样写,你就可以自动重新加载:

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

我看到的唯一问题是变量module,但是我现在正在研究它。


7

nodemon是一个伟大的。我只是添加更多用于调试和监视选项的参数。

package.json

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

命令: nodemon --watch server --inspect ./server/server.js

鉴于:

--watch server重新启动应用程序时更改.js.mjs.coffee.litcoffee,并.json在文件中的server文件夹(包括子文件夹)。

--inspect 启用远程调试。

./server/server.js 入口点。

然后将以下配置添加到launch.json(VS Code),并随时开始调试。

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

请注意,最好将其安装nodemon为项目的dev依赖项。因此,您的团队成员无需安装它或记住命令参数,他们只需npm run dev开始进行黑客攻击。

nodemon文档上查看更多信息:https : //github.com/remy/nodemon#monitoring-multiple-directories


最新版本的nodemon(至少1.19.0)不支持Globbing。只需使用nodemon --watch server --inspect ./server/server.js代替。
亚历克斯

感谢@Alex提供您的信息。更新了答案。
Ninh Pham

5

有一个最近的线程关于Node.js的邮件列表,在这个问题上。简短的答案是不,目前无法自动重新加载所需的文件,但是一些人已经开发了添加此功能的补丁程序。


1
+1是。我参加了讨论。我承认我的解决方案太简单了。仅当热模块本身不需要其他模块时,它才起作用。Felix的解决方案经过深思熟虑,但对于auto- reload是否真正属于核心存在争议。
2010年

5

解决此问题的另一种方法是永远使用

Forever的另一个有用功能是,可以在任何源文件已更改时重新启动应用程序。这使您无需每次添加功能或修复错误时都手动重新启动。要在此模式下永久启动,请使用-w标志:

forever -w start server.js

奇怪的是-w标志,我的express.js应用程序不使用CSS。
2015年

5

node-dev很棒。npminstall node-dev

重新加载服务器时,它甚至会发出桌面通知,并会在消息中显示成功或错误。

使用以下命令在命令行中启动您的应用程序:

node-dev app.js


3

是有关节点热重装的博客文章。它提供了一个github Node分支,可用于替换Node的安装以启用热重装。

从博客:

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

现在,您每次修改myRequestHandler.js时,上面的代码都会注意到并用新代码替换本地requestHandler。任何现有请求将继续使用旧代码,而任何新的传入请求将使用新代码。所有这些都无需关闭服务器,弹跳任何请求,过早地终止任何请求,甚至无需依靠智能负载平衡器。


此解决方案的唯一作用是它是旧版本Node的分支,因此在使用之前必须对其进行调整并与最新版本合并(除非您不介意使用旧版本的Node)。
Chetan

3

我正在做一个很小的节点“事物”,该事物能够随意加载/卸载模块(因此,例如,您可以重启应用程序的一部分而无需关闭整个应用程序)。我并入了一个(非常愚蠢的)依赖管理,因此,如果您要停止一个模块,则所有依赖该模块的模块也将停止。

到目前为止一切顺利,但是后来我偶然发现了如何重新加载模块的问题。显然,可以从“ require”缓存中删除该模块并完成工作。由于我不希望直接更改节点源代码,因此我提出了一个非常 hacky的技巧:在堆栈中搜索,跟踪对“ require”函数的最后一次调用,获取对其“ cache”字段的引用并且..well,删除对该节点的引用:

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

实际上,甚至更容易:

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

显然,这很好。我完全不知道arguments [“ 1”]是什么意思,但是它正在发挥作用。我相信节点专家将有一天实现重载功能,因此我认为目前该解决方案也是可以接受的。(顺便说一句,我的“东西”将在这里:https : //github.com/cheng81/wirez,请在几周内到那里,您应该明白我在说什么)


..当然不是那么简单。仅在调用堆栈中要求调用的情况下才有效。哦,好了,在hack之上轻松进行hack:用临时脚本编写这些东西,并在运行时需要它。做到了,它起作用了..甚至可以从缓存中清除自身
cheng81 2011年

而且实际上更容易:delete(require.cache [moduleFullpathAndExt])
cheng81 2011年

实际上,Node.js模块包装在一个匿名函数中,这是完成模块封装的方式。每个模块实际上看起来像function (module, require) { /* your code */ }。考虑到这一点时,arguments[1]指向require。而while循环则适用于您在模块中的另一个函数中调用它的情况(它只是进入函数层次结构并检查传递给每个函数的参数值)。
JK

3

您可以使用nodemonNPM。如果使用Express Generator,则可以在项目文件夹中使用以下命令:

nodemon npm start

或使用调试模式

DEBUG=yourapp:* nodemon npm start

您也可以直接运行

nodemon your-app-file.js

希望能有所帮助。


1

解决方案位于:http : //github.com/shimondoodkin/node-hot-reload

请注意,您必须自己保管所用的参考文献。

这意味着如果您这样做:var x = require('foo'); y = x; z = x.bar; 然后热装它。

这意味着您必须替换存储在x,y和z中的引用。在热重载回调函数中。

有人将热重加载与自动重启混淆了。我的nodejs-autorestart模块还具有upstart集成,可以在启动时启用自动启动。如果您的应用程序较小,则自动重新启动是可以的,但是,如果您的应用程序较大,则热重新加载更为合适。仅仅是因为热装更快。

我也喜欢我的节点流入模块。


1

不必使用nodemon或类似的其他工具。只需使用您的IDE的功能。

最好的一种是IntelliJ WebStorm,它具有针对node.js的热重装功能(服务器和浏览器自动重装)。


1

这是在Windows中使用的低技术方法。将其放在一个名为的批处理文件中serve.bat

@echo off

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

现在,不要node app.js从cmd shell运行,而要运行serve app.js

这将打开一个运行服务器的新外壳窗口。批处理文件将一直阻塞(由于/wait),直到您关闭shell窗口为止,此时原始cmd shell将询问“终止批处理作业(Y / N)?”。如果您回答“ N”,则服务器将重新启动。

每次您要重新启动服务器时,请关闭服务器窗口并在cmd shell中回答“ N”。


1

我的应用程序结构:

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

首先使用以下命令安装reload

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

然后更改package.json

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

现在,您必须在服务器文件中使用reload :

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

对于最后的更改,响应结束时发送以下脚本

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

现在使用以下代码启动您的应用:

npm start

这种方法行不通,但是,在npmjs.com/package/reload(对于Express应用程序)中引出的方法行得通
Maxie Berkmann

0

用这个:

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

您现在要做的就是:

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

和配置将自动被重新加载:)


有一个不依赖Node框架的版本吗?
阿德里安

0

loaddir是我递归快速加载目录的解决方案。

可以返回

{ 'path/to/file': 'fileContents...' } 要么 { path: { to: { file: 'fileContents'} } }

callback更改文件时将调用它。

它处理文件足够大watch而在写入完成之前被调用的情况。

我已经在项目中使用了大约一年的时间,最近才向它添加了承诺。

帮我战斗测试吧!

https://github.com/danschumann/loaddir


0

您可以使用自动重新加载来重新加载模块,而无需关闭服务器。

安装

npm install auto-reload

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

结果:

{ 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

另一个简单的解决方案是使用fs.readFile代替使用require, 您可以保存包含json对象的文本文件,并在服务器上创建一个间隔以重新加载该对象。

优点:

  • 无需使用外部库
  • 与生产相关(更改时重新加载配置文件)
  • 易于实施

缺点:

  • 您无法重新加载模块-仅包含键值数据的json

0

对于使用Vagrant和PHPStorm的人,文件监视程序是一种更快的方法

  • 禁用文件的立即同步,因此您仅在保存时运行命令,然后为* .js文件和工作目录创建范围并添加此命令

    流浪者ssh -c“ /var/www/gadelkareem.com/forever.sh重新启动”

在forever.sh哪里

#!/bin/bash

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

0

我最近遇到了这个问题,因为通常的嫌疑人都没有使用链接包。如果您像我一样,并且npm link在开发过程中充分利用了它来有效地处理由许多程序包组成的项目,那么依赖关系中发生的更改也会触发重新加载,这一点很重要。

在尝试了node-mon和pm2之后,即使按照他们的指示另外监视node_modules文件夹,他们仍然没有选择更改。尽管此处的答案中有一些自定义解决方案,但对于像这样的事情,单独的包装会更清洁。我今天遇到了node-dev,它不需要任何选项或配置即可完美运行。

从自述文件:

与supervisor或nodemon之类的工具相比,它不会在文件系统中扫描要监视的文件。相反,它挂接到Node的require()函数中,以仅查看实际需要的文件。


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

您可以使用browser-refresh做到这一点。您的节点应用程序会自动重新启动,浏览器中的结果页面也会自动刷新。缺点是您必须将js代码段放在生成的页面上。这是工作示例的仓库

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

我尝试过pm2:安装也很容易并且易于使用;结果令人满意。但是,我们必须照顾到想要的pm2版本。pm 2 runtime是免费版本,而pm2 plus和pm2 enterprise不是免费版本。

至于Strongloop,我的安装失败或未完成,所以我无法使用它。


-1

如今,已使用带有hot选项的WebPack开发服务器。您可以在package.json中添加这样的脚本:"hot": "cross-env NODE_ENV=development webpack-dev-server --hot --inline --watch-poll",

文件中的每个更改都会自动触发重新编译


2
这个问题的答案是错误的。Webpack用于前端应用程序,而开发服务器本身就是一个Web服务器。问题是指向在Node中实现的服务器应用程序。它不需要网络服务器。已经是一个了。
DanielKhan
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.