如何在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()语句中得到一个错误,说“要求”没有定义。process.compile正在执行app.js,但没有关于node.js全局变量的线索。

436768 次浏览

node.js邮件列表中最近(2009年)有一个关于这个主题的线程。简短的回答是否定的,目前还不可能自动重载所需的文件,但一些人已经开发了添加此功能的补丁。

您可以通过Node-Supervisor进行安装

npm install supervisor

看到# EYZ0

在这里是一篇关于节点热重载的博客文章。它提供了github节点分支,您可以使用它来替换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时,上面的代码将不再生效,并用新代码重新放置本地的re-questHandler。任何已存在的请求将继续使用旧代码,而任何新的请求将使用新代码。所有这些都不需要关闭服务器,不需要反弹任何请求,不需要提前终止任何请求,甚至不需要依赖内置的负载均衡器。

< p >解决方案: # EYZ0 < / p >

注意,您必须自己注意所使用的引用。

,这意味着如果你做了:var x=require('foo');y = x, z = x.bar;然后热装 它。< / p >

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

有些人混淆了热重载和自动重启 我的nodejs-autorestart模块也有upstart集成,可以在引导时自动启动。 如果你有一个小的应用程序自动重启是可以的,但当你有一个大的应用程序热重载是更合适的。很简单,因为热重载更快

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

node-supervisor太棒了

在保存旧版本的节点时重新启动(不建议):

npm install supervisor -g
supervisor app.js

对于npx自带的节点版本,在保存时重新启动:

npm install supervisor
npx supervisor app.js

或者直接在npm脚本中调用supervisor:

"scripts": {
"start": "supervisor app.js"
}

我正在制作一个相当小的节点“东西”,能够加载/卸载模块(所以,也就是说,你可以重新启动你的应用程序的一部分,而不会使整个应用程序关闭)。 我加入了一个(非常愚蠢的)依赖管理,所以如果你想停止一个模块,所有依赖于它的模块也会被停止 到目前为止还不错,但后来我陷入了如何重新加载模块的问题。显然,只需要从“require”缓存中删除模块就可以完成工作。由于我不热衷于直接改变节点源代码,我提出了一个非常 hack -hack,即:在堆栈中搜索跟踪“require”函数的最后一次调用,抓取对它的“cache”字段的引用和..那么,删除对节点的引用:

    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,去那里在几个星期,你应该看到我在说什么)

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

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

nodemon在谷歌搜索中排在第一位,而且它似乎奏效了:

npm install nodemon -g
cd whatever_dir_holds_my_app
nodemon app.js

如果有人仍然遇到这个问题,并希望仅使用标准模块来解决它,我做了一个简单的例子:

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制作的,它不适合一些特定的需求,但可以在一些简单的应用程序中工作。

< p >更新: 这个函数在我的模块更简单的GitHub回购

中实现

supervisor的一个好的、最新的替代方案是nodemon:

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

使用nodemon的节点版本没有npx (v8.1及以下,不建议):

$ npm install nodemon -g
$ nodemon app.js

或者使用nodemon和捆绑在(v8.2+)中npx的Node版本:

$ npm install nodemon
$ npx nodemon app.js

或者在package.json中作为一个npm脚本中的devDependency:

"scripts": {
"start": "nodemon app.js"
},
"devDependencies": {
"nodemon": "..."
}

用这个:

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

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

加载器是我的解决方案快速加载一个目录,递归。

可以返回

< p > # EYZ0 或 # EYZ0 < / p >

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

它处理的情况是文件足够大,以至于在写入完成之前就调用watch

我已经在项目中使用它一年左右了,最近才添加了承诺。

帮我进行战斗测试!

https://github.com/danschumann/loaddir

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

安装

npm install auto-reload

例子

data.json

{ "name" : "Alan" }

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

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

优点:

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

缺点:

  • 你不能重载一个模块——只能重载一个包含键值数据的json

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

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

    Vagrant SSH -c "/var/www/gadelkareem.com/forever.sh restart"

forever.sh在哪里

#!/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,它在没有任何选项或配置的情况下工作得很好。

自述:

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

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

Forever的另一个有用的功能是它可以选择重新启动 当任何源文件发生更改时,您的应用程序。这让你自由 从每次添加功能或修复错误时都必须手动重新启动 bug。要在此模式下启动Forever,使用-w标志:

forever -w start server.js

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

可能最好的一个是IntelliJ WebStorm热重载功能(自动服务器和浏览器重载)的node . js

节点开发工作得很好。npm # EYZ0

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

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

# EYZ0

nodemon是一个很棒的例子。我只是为调试和监视选项添加了更多参数。

package.json

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

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

而:

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

--inspect开启远程调试。

入口点。

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

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

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

查看更多关于nodemon文档:https://github.com/remy/nodemon#monitoring-multiple-directories

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

. json: "hot": "cross-env NODE_ENV=development webpack-dev-server --hot --inline --watch-poll",

文件中的每一个变化都会自动触发重新编译

你可以从NPM使用nodemon。 如果你正在使用Express生成器,那么你可以在你的项目文件夹中使用这个命令:

nodemon npm start

或使用调试模式

DEBUG=yourapp:* nodemon npm start

你也可以直接运行

nodemon your-app-file.js

希望这对你有所帮助。

这里有一个在Windows中使用的低技术方法。把它放在一个名为serve.bat的批处理文件中:

@echo off


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

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

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

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

我的应用结构:

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

你可以使用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}/` })
}


});

我尝试过pm2:安装很简单,也很容易使用;结果令人满意。但是,我们必须考虑我们想要哪个版本的pm2。PM 2运行时是免费版,而pm2 plus和pm2 enterprise则不是免费的。

至于Strongloop,我的安装失败或没有完成,所以我不能使用它。

如果你谈论的是服务器端NodeJS热加载,假设你希望在服务器上有一个Javascript文件,它有一个描述了快速路由的Javascript文件,你希望这个Javascript文件热加载,而不是在文件更改时服务器重新启动,那么旋转木马可以做到这一点。

basic-server就是一个例子

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

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

这意味着您可以编写一个REST服务器,它可以使用这个razzle进行热重载。

这是相当简单的,只是做这个自己没有任何依赖…内置的文件监视器已经足够成熟,它不像以前那么糟糕

你不需要任何复杂的子进程来生成/杀死&将STD输入/输出…你只需要一个简单的网络工作者,这就是全部!web Worker也是我在浏览器中使用的工具…所以坚持使用网络技术吧!Worker也将登录到控制台

import { watch } from 'node:fs/promises'
import { Worker } from 'node:worker_threads'


let worker = new Worker('./app.js')


async function reloadOnChange (dir) {
const watcher = watch(dir, { recursive: true })
for await (const change of watcher) {
if (change.filename.endsWith('.js')) {
worker.terminate()
worker = new Worker('./app.js')
}
}
}


// All the folder to watch for
['./src', './lib', './test'].map(reloadOnChange)

这可能不是最好的解决方案,如果你使用javascript以外的任何东西,不依赖于一些构建过程。

在Node.js 19中,您可以使用--watch选项监视文件更改。文件更改后,进程将自动重新启动,反映新的更改。

node --watch server.js

长期以来,Nodemon一直是重新启动服务器进行文件更改的首选。现在在Node.js 19中,他们引入了--watch标志,它做了同样的[实验]。# EYZ1

node --watch index.js