ChatGPT解决这个技术问题 Extra ChatGPT

如何在 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 全局变量一无所知。

您知道您可以在每个请求上运行此代码:Object.keys(require.cache).forEach(function(key) { delete require.cache[key]; });
为什么你有两个js文件,app.js作为服务器文件应该就够了?

M
Mike 'Pomax' Kamermans

nodemonsupervisor 的一个很好的最新替代方案:

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

要将 nodemon 与不带 npx 的 Node 版本一起使用(v8.1 及更低版本,不建议):

$ npm install nodemon -g
$ nodemon app.js

或者将 nodemon 与带有 npx 的 Node 版本一起使用(v8.2+):

$ npm install nodemon
$ npx nodemon app.js

或者使用 package.json 中的 npm 脚本作为 devDependency:

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

如果您想在 Nitrous.io - $ nodemon -L yourfile.js 中使用它(完整说明在 coderwall.com/p/aqxl_q
但在这种情况下,它也会重新启动服务器进程。
automatically restart the server - perfect for development 太夸张了。重新加载服务器可能意味着登录后端服务,这在我的情况下确实需要很长时间。 “完美的开发”类似于热重载类,而进程在内存中运行而不会丢失状态,就像你更改源代码时 android studio 所做的那样。
使用 npm install [--save-dev | -D] nodemon 将安装限制在项目范围内。
这只会重新启动服务器,仍然需要手动重新加载 Web 客户端。
M
Mike 'Pomax' Kamermans

node-supervisor 很棒

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

npm install supervisor -g
supervisor app.js

对于 npx 附带的 Node 版本,用于在保存时重新启动:

npm install supervisor
npx supervisor app.js

或直接在 npm 脚本中调用 supervisor

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

npm install -g 主管。它应该全局安装。
在 OSx 10.2.8 上,我必须使用 sudo 运行它
必须在 Windows 下像这样运行它:"C:\Program Files\nodejs\node.exe" C:\Users\Mark\AppData\Roaming\npm\node_modules\supervisor\lib\cli-wrapper.js app.js
在应用程序根目录中没有 -g 或 sudo:npm install supervisornode node_modules/supervisor/lib/cli-wrapper.js app.js(我有一个非根节点安装)
@Mark 这意味着节点不在您的 PATH
I
Inshua

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

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

如果您想在不重新启动应用程序的情况下重新加载外部库(在我的例子中是一个 IRC 机器人),这非常棒。
这太棒了!如此简单,效果很好。每当有请求进来时,我都会取消缓存一堆没有状态的文件。
delete require.cache[require.resolve('./mymodule.js')]; 处理真实路径
这是安全的做法还是被认为是“不好的做法”或“仅限开发”?
@jocull 我认为它不安全,因为它可能会重新创建类和函数或任何导出,与 === 比较时会导致不同的引用
C
Cristian Gutu

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

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 中实现


这是一个伟大而简单的解决方案。我只是将它用于一个机器人,当主持人告诉它时,它应该从 git 进行自我更新。问题是,一旦您进入应用程序,您就无法重新启动自己。但是,我可以使用您的方法生成机器人实例并观察点文件。然后机器人会自我更新,接触点文件,并由启动器自动重新启动。惊人的!
@Fred 我很高兴听到这个:) 我将在一个模块中实现这个解决方案,很快我想,我有更多的想法来扩展它的功能
如果不需要文件 watch,可以通过侦听不同的信号,在没有 fs 的情况下重新加载。
J
JnBrymn

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

npm install nodemon -g
cd whatever_dir_holds_my_app
nodemon app.js

N
Ninh Pham

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

包.json

  "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 Code)并随时开始调试。

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

请注意,最好将 nodemon 安装为项目的开发依赖项。因此,您的团队成员不需要安装它或记住命令参数,他们只需 npm run dev 并开始破解。

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


最新版本的 nodemon(至少 1.19.0)不支持通配。只需使用 nodemon --watch server --inspect ./server/server.js 代替。
感谢@Alex 提供您的信息。更新了答案。
有没有办法通过重建对反应应用程序中任何客户端文件的任何更改来重建应用程序?
R
Richard Metzler

您可以通过以下方式安装 Node-Supervisor

npm install supervisor

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


如果服务器崩溃,更多的是关于重新启动服务器。当监视的文件发生变化时,node-supervisor 也会重新启动整个过程。它不是严格意义上的热重载。
虽然不是真正的热加载,但如果您只想在开发时自动重新加载代码,那么这个工具非常有用,这样您就不必在每次更改后在命令行中重新启动节点。
O
Owais Qureshi

node-dev 效果很好。 npm install node-dev

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

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

node-dev app.js


a
azwar_akbar

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

nodemon npm start

或使用调试模式

DEBUG=yourapp:* nodemon npm start

也可以直接运行

nodemon your-app-file.js

希望这有帮助。


如果您键入 set DEBUG=myapp:* & nodemon npm start,这适用于 Windows
我还必须按照这些说明全局安装 nodemon stackoverflow.com/a/40359656/74585
我使用了快速生成器,nodemon npm start 确实有效,谢谢
M
Mike 'Pomax' Kamermans

在 node.js 邮件列表中,最近 (2009) thread 有一篇关于此主题的文章。简短的回答是否定的,目前无法自动重新加载所需的文件,但有几个人开发了添加此功能的补丁。


+1 是的。我参加了讨论。我承认我的解决方案太简单了。它仅在热模块本身不需要其他模块时才有效。 Felix 的解决方案经过深思熟虑,但自动重载是否真的属于核心存在争议。
T
Teoman shipahi

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

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

forever -w start server.js

奇怪的是 -w 标志我的 express.js 应用程序不使用 CSS。
'forever' 不是内部或外部命令、可运行程序或批处理文件。
C
Chetan

Here 是一篇关于 Node.js 热重载的博文。它提供了一个 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。任何现有请求将继续使用旧代码,而任何新传入请求将使用新代码。所有这些都无需关闭服务器、退回任何请求、过早终止任何请求,甚至无需依赖智能负载均衡器。


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

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

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

var args = 参数 while(!args['1'] || !args['1'].cache) { args = args.callee.caller.arguments } var cache = args['1'].cache util.log ('删除缓存' + moduleFullpathAndExt)删除(缓存[moduleFullpathAndExt])

实际上更容易:

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

显然,这工作得很好。我完全不知道那个 arguments["1"] 是什么意思,但它正在做它的工作。我相信节点人员有一天会实施重新加载工具,所以我想现在这个解决方案也是可以接受的。 (顺便说一句。我的“东西”会在这里:https://github.com/cheng81/wirez,几周后去那里,你应该明白我在说什么)


..当然不是那么简单。仅当调用堆栈中有对 require 的调用时才有效。哦,好吧,在 hack 之上轻松 hack:在临时脚本中编写这些东西,并在运行时需要它。做到了,它有效..它甚至从缓存中清除了自己
实际上它更容易:delete(require.cache[moduleFullpathAndExt])
Node.js 模块实际上包装在一个匿名函数中,这就是模块封装的完成方式。每个模块实际上看起来像 function (module, require) { /* your code */ }。考虑到这一点,arguments[1] 指向 require。 while 循环适用于从模块中的另一个函数中调用它的情况(它只是向上函数层次结构并检查传递给每个函数的参数值)。
S
Shimon Doodkin

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

请注意,您必须自己处理所使用的参考。

这意味着如果你这样做了: var x=require('foo'); y=x;z=x.bar;并热重新加载它。

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

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

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


这是一个不错的!
这是旧的对不起
l
lukyer

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

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


y
yoyo

这是一种在 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”。


K
Kasra Karami

我的应用程序结构:

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

这种方法不起作用,但是,npmjs.com/package/reload 中介绍的方法(用于 Express 应用程序)可以。
此方法效果很好,我在您可以在此路径中看到的项目中使用此方法:github.com/KasraK2K/imensite-tutorial-site
J
Jan Pi

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

});

o
offlinehacker

用这个:

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 一部分的框架的版本?
d
dansch

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

可以返回

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

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

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

我在项目中使用它已经有一年左右的时间了,最近才向它添加了 Promise。

帮我战测吧!

https://github.com/danschumann/loaddir


L
Lellansin

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

安装

npm install auto-reload

例子

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

I
Imri

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

优点:

无需使用外部库

与生产相关(更改时重新加载配置文件)

易于实施

缺点:

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


G
Gadelkareem

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

禁用文件的立即同步,因此您仅在保存时运行命令,然后为 *.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

A
Aaron Storck

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

在尝试了 node-mon 和 pm2 之后,即使按照他们的指示额外查看 node_modules 文件夹,他们仍然没有接受更改。尽管这里的答案中有一些自定义解决方案,但对于这样的事情,单独的包更干净。我今天遇到了 node-dev,它无需任何选项或配置即可完美运行。

从自述文件:

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


L
Lex Soft

我试过 pm2 :安装简单易用;结果令人满意。但是,我们必须处理我们想要的 pm2 版本。 pm 2 runtime 是免费版,而 pm2 plus 和 pm2 enterprise 不是免费的。

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


P
Phil

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

一个例子是基本服务器

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 服务器进行编程。


e
eKelvin

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

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


这个答案是错误的。 Webpack 用于前端应用程序,而开发服务器本身就是一个网络服务器。问题是指在 Node.js 中实现的服务器应用程序。它不需要网络服务器。已经是一个了。
B
BottleLiu
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;
};