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

时间:2009-12-29 00:08:49

标签: javascript node.js

关于如何在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全局变量没有任何线索。

29 个答案:

答案 0 :(得分:452)

supervisor的最新替代方案 nodemon

  

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

使用nodemon

$ npm install nodemon -g
$ nodemon app.js

答案 1 :(得分:305)

node-supervisor很棒

在保存时重启的用法:

npm install supervisor -g
supervisor app.js

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

答案 2 :(得分:81)

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

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

答案 3 :(得分:18)

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

npm install nodemon -g
cd whatever_dir_holds_my_app
nodemon app.js

答案 4 :(得分:17)

如果有人仍然提出这个问题而想要仅使用标准模块来解决它,我就做了一个简单的例子:

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

中实现

答案 5 :(得分:8)

您可以通过

安装Node-Supervisor
npm install supervisor

请参阅http://github.com/isaacs/node-supervisor

答案 6 :(得分:7)

修改:我的回答已经过时了。 Node.js是一种快速变化的技术。

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

require(url, reload)

要在当前目录中重新加载app.js

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

写下这样的内容,你有自动 -reload:

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

我看到的唯一问题是变量module,但我现在正在努力。

答案 7 :(得分:5)

在node.js邮件列表上有关于此主题的最新thread。简短的回答是否定的,目前不可能自动重新加载所需的文件,但有几个人开发了添加此功能的补丁。

答案 8 :(得分:5)

此问题的另一个解决方案是使用forever

  

Forever的另一个有用功能是可以选择重启   任何源文件发生更改时的应用程序。这让你松了一口气   从每次添加功能或修复时手动重启   错误。要在此模式下启动Forever,请使用-w标志:

forever -w start server.js

答案 9 :(得分:4)

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更改{{1}中的.js.mjs.coffee.litcoffee.json文件时重新启动应用}文件夹(包含子文件夹)。

server启用远程调试。

--inspect切入点。

然后将以下配置添加到./server/server.js(VS代码)并随时开始调试。

launch.json

请注意,安装{ "type": "node", "request": "attach", "name": "Attach", "protocol": "inspector", "port": 9229 } 作为项目的开发人员依赖关系会更好。因此,您的团队成员不需要安装或记住命令参数,他们只是nodemon并开始黑客攻击。

详情请见npm run dev文档:https://github.com/remy/nodemon#monitoring-multiple-directories

答案 10 :(得分:3)

我正在努力制作一个相当小的节点“东西”,它能够随意加载/卸载模块(因此,你可以重新启动部分应用程序,而无需关闭整个应用程序)。 我正在整合一个(非常愚蠢的)依赖管理,所以如果你想停止一个模块,所有依赖于它的模块也会被停止。

到目前为止一直很好,但后来我偶然发现了如何重新加载模块的问题。显然,可以从“require”缓存中删除模块并完成工作。由于我不想直接更改节点源代码,我想出了一个非常 hacky-hack,即:在堆栈中搜索跟踪最后一次调用“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 ] )
}

显然,这很好用。我完全不知道那些论点[“1”]意味着什么,但它正在做它的工作。我相信节点人员有一天会实现重装设备,所以我想现在这个解决方案也是可以接受的。 (顺便说一句。我的“事情”将会在这里:https://github.com/cheng81/wirez,过几个星期去那里,你应该看看我在说什么)

答案 11 :(得分:3)

Here是一篇关于Hot Reloading for Node的博客文章。它提供了github Node branch,您可以使用它来替换您的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。任何现有请求将继续使用旧代码,而任何新传入请求将使用新代码。所有这些都没有关闭服务器,反弹任何请求,过早地杀死任何请求,甚至依赖智能负载均衡器。

答案 12 :(得分:3)

node-dev工作得很好。 npm install node-dev

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

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

node-dev app.js

答案 13 :(得分:2)

您可以使用 NPM 中的 nodemon 。 如果您使用的是Express generator,则可以在项目文件夹中使用以下命令:

nodemon npm start

或使用调试模式

DEBUG=yourapp:* nodemon npm start

您也可以直接运行

nodemon your-app-file.js

希望获得帮助。

答案 14 :(得分:1)

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

请注意您必须自己照顾所使用的参考资料。

这意味着如果你这样做:var x = require('foo'); Y = X; Z = x.bar;和热重新加载 它

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

有些人将热重载与自动重启混淆 我的nodejs-autorestart模块还具有upstart集成,可以在启动时启用自动启动。 如果你有一个小应用程序自动重启是好的,但是当你有一个大的应用程序热重新加载更合适。只是因为热重载更快。

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

答案 15 :(得分:1)

这是在Windows中使用的技术含量较低的方法。将其放入名为serve.bat的批处理文件中:

@echo off

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

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

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

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

答案 16 :(得分:1)

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

对于 node.js ,可能最好的是 IntelliJ WebStorm ,具有热重新加载功能(自动服务器和浏览器重新加载)。

答案 17 :(得分:0)

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

对于Strongloop,我的安装失败或未完成,因此无法使用。

答案 18 :(得分:0)

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

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

});

答案 19 :(得分: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;
};

答案 20 :(得分:0)

我的应用程序结构:

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

首先使用以下命令安装重新加载

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

答案 21 :(得分:0)

如果您谈论服务器端 NodeJS 热重载,假设您希望在服务器上有一个 Javascript 文件,其中描述了一个快速路由,并且您希望此 Javascript 文件热重载而不是服务器重新启动文件更改然后 razzle 可以做到这一点。

一个例子是基本服务器

https://github.com/jaredpalmer/razzle/tree/master/examples/basic-server

文件https://github.com/jaredpalmer/razzle/blob/master/examples/basic-server/src/server.js如果被更改和保存将热重载,服务器不会重新启动。

这意味着您可以编写一个可以使用此 razzle 进行热加载的 REST 服务器。

答案 22 :(得分:0)

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

在尝试了node-mon和pm2之后,即使按照他们的指示进行额外观察node_modules文件夹,他们仍然没有获取更改。虽然这里的答案中有一些自定义解决方案,但对于类似的东西,单独的包更清洁。我今天遇到了node-dev,它完美无缺,没有任何选项或配置。

来自自述文件:

  

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

答案 23 :(得分:0)

对于使用Vagrant和PHPStorm的人来说,file watcher是一种更快的方法

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

    vagrant ssh -c&#34; /var/www/gadelkareem.com/forever.sh restart&#34;

其中forever.sh就像

#!/bin/bash

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

答案 24 :(得分:0)

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

的优点:

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

缺点:

  • 您无法重新加载模块 - 只是一个包含键值数据的json

答案 25 :(得分: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' }

答案 26 :(得分:0)

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

可以返回

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

文件发生变化时会调用callback

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

我在项目中使用它已经有一年左右的时间了,最​​近又添加了承诺。

帮我战斗吧!

https://github.com/danschumann/loaddir

答案 27 :(得分: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");

并且config会自动重新加载:)

答案 28 :(得分:-1)

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

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