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

How to auto-reload files in Node.js?

关于如何在Node.js中实现文件自动重载的任何想法? 每次更改文件时,我都厌倦了重启服务器。
显然Node.js'require()函数如果已经被要求则不会重新加载文件,所以我需要做这样的事情:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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文件中我有:

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

但是这也没有用 - 我在process.compile()语句中得到一个错误,说'require'没有定义。 process.compile正在评估app.js,但没有关于node.js全局变量的线索。


supervisor的一个好的,最新的替代是nodemon

Monitor for any changes in your node.js application and automatically restart the server - perfect for development

要使用nodemon

1
2
$ npm install nodemon -g
$ nodemon app.js

node-supervisor太棒了

用于在保存时重启:

1
2
npm install supervisor -g
supervisor app.js

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


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

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

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

1
2
3
npm install nodemon -g
cd whatever_dir_holds_my_app
nodemon app.js


如果有人仍然只是使用标准模块来解决这个问题我做了一个简单的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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循环获取所有文件名,或者通过查看目录:

1
2
3
4
5
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编写的,它不适合某些特定需求,但可以在一些简单的应用程序中使用。

更新:
这个功能在我的模块simpleR,GitHub repo中实现


您可以安装Node-Supervisor

1
npm install supervisor

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


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

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

1
require(url, reload)

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

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

写这样的东西,你有自动重新加载:

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

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


这个问题的另一个解决方案是永远使用

Another useful capability of Forever is that it can optionally restart
your application when any source files have changed. This frees you
from having to manually restart each time you add a feature or fix a
bug. To start Forever in this mode, use the -w flag:

1
forever -w start server.js

nodemon是一个很棒的人。 我只是为调试和观看选项添加了更多参数。

的package.json

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

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

鉴于:

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

--inspect启用远程调试。

./server/server.js切入点。

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

1
2
3
4
5
6
7
{
   "type":"node",
   "request":"attach",
   "name":"Attach",
   "protocol":"inspector",
   "port": 9229
}

请注意,最好将nodemon安装为项目的dev依赖项。 所以你的团队成员不需要安装它或记住命令参数,他们只是npm run dev并开始黑客攻击。

有关nodemon docs的更多信息,请访问:https://github.com/remy/nodemon#monitoring-multiple-directories


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


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

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

在命令行上启动您的应用程序:

node-dev app.js


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

到目前为止一切顺利,但后来我偶然发现了如何重新加载模块的问题。显然,可以从"require"缓存中删除模块并完成工作。由于我不想直接更改节点源代码,我想出了一个非常hacky-hack,即:在堆栈中搜索最后一次调用"require"函数,获取对它的"cache"字段的引用and..well,删除对节点的引用:
<击>

1
2
3
4
5
6
7
    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 ] )


实际上更容易:

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

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


您可以使用NPM中的nodemon。
如果您使用Express生成器,那么您可以在项目文件夹中使用此命令:

1
nodemon npm start

或使用调试模式

1
DEBUG=yourapp:* nodemon npm start

你也可以直接跑

1
nodemon your-app-file.js

希望这有帮助。


这是一篇关于Hot Reloading for Node的博客文章。 它提供了一个github Node分支,您可以使用它来替换Node的安装以启用Hot Reloading。

来自博客:

1
2
3
4
5
6
7
8
9
10
11
12
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);

Now, any time you modify myRequestHandler.js, the above code will no-tice and re-place the local re-questHandler with the new code. Any ex-ist-ing re-quests will con-tin-ue to use the old code, while any new in-com-ing re-quests will use the new code. All with-out shut-ting down the serv-er, bounc-ing any re-quests, pre-ma-ture-ly killing any re-quests, or even re-ly-ing on an in-tel-li-gent load bal-ancer.


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

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


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

请注意,您必须自己照顾所使用的参考文献。

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

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

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

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


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

1
2
3
4
5
@echo off

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

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

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

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


我的app结构:

1
2
3
4
5
6
NodeAPP (folder)
   |-- app (folder)
      |-- all other file is here
   |-- node_modules (folder)
   |-- package.json
   |-- server.js (my server file)

首先使用此命令重新加载:

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

然后改变package.json:

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

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

1
2
3
4
5
6
7
8
9
10
11
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);

对于最后一次更改,您的响应结束发送此脚本:

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

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

1
npm start

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

安装

1
npm install auto-reload

data.json

1
{"name" :"Alan" }

test.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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);

结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{ 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' }


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

可以回来

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

它有callback,当文件被更改时将被调用。

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

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

帮我战斗吧!

https://github.com/danschumann/loaddir


1
2
3
4
5
6
7
8
9
10
11
12
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;
};

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

优点:

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

缺点:

  • 你不能重新加载一个模块 - 只是一个包含键值数据的json

对于使用Vagrant和PHPStorm的人来说,文件观察器是一种更快的方法

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

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

forever.sh就像

1
2
3
#!/bin/bash

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

我最近提出这个问题,因为通常的嫌疑人没有使用链接包。 如果你像我一样,并且在开发过程中利用npm link来有效地处理由许多软件包组成的项目,那么依赖项中发生的更改也会引发重新加载。

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

从自述文件:

In contrast to tools like supervisor or nodemon it doesn't scan the filesystem for files to be watched. Instead it hooks into Node's require() function to watch only the files that have been actually required.


用这个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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));
}

你现在要做的就是:

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

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


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

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