简体   繁体   English

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

[英]How to auto-reload files in Node.js?

Any ideas on how I could implement an auto-reload of files in Node.js?关于如何在 Node.js 中实现文件自动重新加载的任何想法? I'm tired of restarting the server every time I change a file.每次更改文件时我都厌倦了重新启动服务器。 Apparently Node.js' require() function does not reload files if they already have been required, so I need to do something like this:显然 Node.js 的require() function 不会重新加载已经需要的文件,所以我需要这样做:

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

And in the app.js file I have:app.js文件中,我有:

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

But this also isn't working - I get an error in the process.compile() statement saying that 'require' is not defined.但这也不起作用 - 我在process.compile()语句中收到一个错误,指出未定义“require”。 process.compile is evaling the app.js , but has no clue about the node.js globals. process.compile正在评估app.js ,但对 node.js 全局变量一无所知。

A good, up to date alternative to supervisor is nodemon :一个很好的、最新的supervisor替代品是nodemon

Monitor for any changes in your node.js application and automatically restart the server - perfect for development监视 node.js 应用程序中的任何更改并自动重新启动服务器 - 非常适合开发

To use nodemon :要使用nodemon

$ npm install nodemon -g
$ nodemon app.js

node-supervisor is awesome节点主管很棒

usage to restart on save:保存时重新启动的用法:

npm install supervisor -g
supervisor app.js

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

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

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

If somebody still comes to this question and wants to solve it using only the standard modules I made a simple example:如果有人仍然遇到这个问题并且只想使用标准模块来解决它,我做了一个简单的例子:

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

This example is only for one file (server.js), but can be adapted to multiple files using an array of files, a for loop to get all file names, or by watching a directory:此示例仅适用于一个文件 (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');    
})

This code was made for Node.js 0.8 API, it is not adapted for some specific needs but will work in some simple apps.此代码是为 Node.js 0.8 API 编写的,它不适用于某些特定需求,但可以在一些简单的应用程序中使用。

UPDATE: This functional is implemented in my module simpleR , GitHub repo更新:这个功能是在我的模块simpleR 中实现的GitHub repo

nodemon came up first in a google search, and it seems to do the trick: nodemon首先出现在谷歌搜索中,它似乎可以解决问题:

npm install nodemon -g
cd whatever_dir_holds_my_app
nodemon app.js

nodemon is a great one. nodemon是一个伟大的。 I just add more parameters for debugging and watching options.我只是为调试和观看选项添加了更多参数。

package.json包.json

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

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

Whereas:鉴于:

--watch server Restart the app when changing .js , .mjs , .coffee , .litcoffee , and .json files in the server folder (included subfolders). --watch server变更时,重新启动该应用.js.mjs.coffee.litcoffee ,并.json文件在server文件夹(包括子文件夹)。

--inspect Enable remote debug. --inspect启用远程调试。

./server/server.js The entry point. ./server/server.js入口点。

Then add the following config to launch.json (VS Code) and start debugging anytime.然后将以下配置添加到launch.json (VS Code) 并随时开始调试。

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

Note that it's better to install nodemon as dev dependency of project.请注意,最好将nodemon安装为项目的 dev 依赖项。 So your team members don't need to install it or remember the command arguments, they just npm run dev and start hacking.所以你的团队成员不需要安装它或记住命令参数,他们只需npm run dev并开始黑客攻击。

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

Edit: My answer is obsolete.编辑:我的答案已过时。 Node.js is a very fast changing technology. Node.js 是一种变化非常快的技术。

I also wondered about reloading modules.我也想知道重新加载模块。 I modified node.js and have published the source at Github at nalply/node .我修改了 node.js 并在 Github 的nalply/node 上发布了源代码。 The only difference is the function require .唯一的区别是函数require It has an optional second argument reload .它有一个可选的第二个参数reload

require(url, reload)

To reload app.js in current directory use要在当前目录中重新加载app.js使用

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

Write something like this, and you have auto -reload:写这样的东西,你有自动重新加载:

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

The only problem I see is the variable module , but I am working at it now.我看到的唯一问题是变量module ,但我现在正在处理它。

There is Node-Supervisor that you can install by您可以安装 Node-Supervisor

npm install supervisor

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

You can use nodemon from NPM .您可以使用来自NPM 的nodemon And if you are using Express generator then you can using this command inside your project folder:如果您使用的是 Express 生成器,那么您可以在项目文件夹中使用此命令:

nodemon npm start

or using Debug mode或使用调试模式

DEBUG=yourapp:* nodemon npm start

you can also run directly也可以直接运行

nodemon your-app-file.js

Hope this help.希望这有帮助。

There was a recent thread about this subject on the node.js mailing list.有一个最近的线程关于Node.js的邮件列表,在这个问题上。 The short answer is no, it's currently not possible auto-reload required files, but several people have developed patches that add this feature.简短的回答是否定的,目前不可能自动重新加载所需的文件,但有几个人已经开发了添加此功能的补丁。

node-dev works great. node-dev 很好用。 npm install node-dev npm install node-dev

It even gives a desktop notification when the server is reloaded and will give success or errors on the message.它甚至会在服务器重新加载时发出桌面通知,并会在消息上显示成功或错误。

start your app on command line with:在命令行上启动您的应用程序:

node-dev app.js

yet another solution for this problem is using forever这个问题的另一个解决方案是永远使用

Another useful capability of Forever is that it can optionally restart your application when any source files have changed. Forever 的另一个有用功能是,当任何源文件发生更改时,它可以有选择地重新启动您的应用程序。 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:要以这种模式启动 Forever,请使用 -w 标志:

forever -w start server.js

Here is a blog post about Hot Reloading for Node. 是一篇关于 Node.js 热重载的博客文章。 It provides a github Node branch that you can use to replace your installation of Node to enable Hot Reloading.它提供了一个github Node 分支,您可以使用它来替换您的 Node 安装以启用热重载。

From the blog:来自博客:

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 notice and replace the local requestHandler with the new code.现在,每当您修改 myRequestHandler.js 时,上面的代码都会注意到并将本地 requestHandler 替换为新代码。 Any existing requests will continue to use the old code, while any new incoming requests will use the new code.任何现有请求将继续使用旧代码,而任何新传入请求将使用新代码。 All without shutting down the server, bouncing any requests, prematurely killing any requests, or even relying on an intelligent load balancer.所有这些都无需关闭服务器、退回任何请求、过早终止任何请求,甚至不依赖于智能负载平衡器。

I am working on making a rather tiny node "thing" that is able to load/unload modules at-will (so, ie you could be able to restart part of your application without bringing the whole app down).我正在制作一个相当小的节点“东西”,它能够随意加载/卸载模块(因此,即您可以重新启动部分应用程序而不会关闭整个应用程序)。 I am incorporating a (very stupid) dependency management, so that if you want to stop a module, all the modules that depends on that will be stopped too.我正在合并一个(非常愚蠢的)依赖管理,所以如果你想停止一个模块,所有依赖于它的模块也将被停止。

So far so good, but then I stumbled into the issue of how to reload a module.到目前为止一切顺利,但后来我偶然发现了如何重新加载模块的问题。 Apparently, one could just remove the module from the "require" cache and have the job done.显然,人们可以从“需要”缓存中删除模块并完成工作。 Since I'm not keen to change directly the node source code, I came up with a very hacky-hack that is: search in the stack trace the last call to the "require" function, grab a reference to it's "cache" field and..well, delete the reference to the node:由于我不想直接更改节点源代码,因此我想出了一个非常hacky-hack:在堆栈中搜索跟踪对“require”函数的最后一次调用,获取对其“缓存”字段的引用和..好吧,删除对节点的引用:

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

Even easier, actually:更简单,实际上:

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

Apparently, this works just fine.显然,这工作得很好。 I have absolutely no idea of what that arguments["1"] means, but it's doing its job.我完全不知道参数 ["1"] 是什么意思,但它正在做它的工作。 I believe that the node guys will implement a reload facility someday, so I guess that for now this solution is acceptable too.我相信节点人总有一天会实现重新加载设施,所以我想现在这个解决方案也是可以接受的。 (btw. my "thing" will be here: https://github.com/cheng81/wirez , go there in a couple of weeks and you should see what I'm talking about) (顺便说一句。我的“东西”将在这里: https : //github.com/cheng81/wirez ,几周后去那里,你应该明白我在说什么)

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

notice that you have to take care by yourself of the references used.请注意,您必须自己注意所使用的引用。

that means if you did : var x=require('foo');这意味着如果你这样做了: var x=require('foo'); y=x;z=x.bar; y=x;z=x.bar; and hot reloaded it.并热重载它。

it means you have to replace the references stored in x, y and z.这意味着您必须替换存储在 x、y 和 z 中的引用。 in the hot reaload callback function.在热重载回调函数中。

some people confuse hot reload with auto restart my nodejs-autorestart module also has upstart integration to enable auto start on boot.有些人将热重载与自动重启混淆了我的 nodejs-autorestart 模块也有 upstart 集成来启用自动启动。 if you have a small app auto restart is fine, but when you have a large app hot reload is more suitable.如果你有一个小应用程序自动重启很好,但是当你有一个大应用程序时热重载更合适。 simply because hot reload is faster.仅仅是因为热重载更快。

Also I like my node-inflow module.我也喜欢我的节点流入模块。

Not necessary to use nodemon or other tools like that.没有必要使用nodemon或其他类似的工具。 Just use capabilities of your IDE.只需使用 IDE 的功能即可。

Probably best one is IntelliJ WebStorm with hot reload feature (automatic server and browser reload) for node.js .可能最好的一个是IntelliJ WebStorm,它具有用于node.js 的热重载功能(自动服务器和浏览器重载)。

Here's a low tech method for use in Windows.这是在 Windows 中使用的低技术方法。 Put this in a batch file called serve.bat :把它放在一个名为serve.bat的批处理文件中:

@echo off

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

Now instead of running node app.js from your cmd shell, run serve app.js .现在不是从你的 cmd shell 运行node app.js ,而是运行serve app.js

This will open a new shell window running the server.这将打开一个运行服务器的新 shell 窗口。 The batch file will block (because of the /wait ) until you close the shell window, at which point the original cmd shell will ask "Terminate batch job (Y/N)?"批处理文件将阻塞(因为/wait ),直到您关闭 shell 窗口,此时原始 cmd shell 将询问“终止批处理作业(是/否)?” If you answer "N" then the server will be relaunched.如果您回答“N”,则服务器将重新启动。

Each time you want to restart the server, close the server window and answer "N" in the cmd shell.每次要重新启动服务器时,请关闭服务器窗口并在 cmd shell 中回答“N”。

my app structure:我的应用程序结构:

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

first install reload with this command:首先使用以下命令安装重新加载

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

then change package.json :然后更改package.json

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

now you must use reload in your server file :现在你必须在你的服务器文件中使用 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);

and for last change, end of your response send this script :对于最后一次更改,响应结束发送此脚本

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

now start your app with this code:现在使用以下代码启动您的应用程序:

npm start

Use this:使用这个:

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

All you have to do now is:您现在要做的就是:

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

And config will automatically get reloaded :)并且配置将自动重新加载:)

loaddir is my solution for quick loading of a directory, recursively. loaddir 是我的递归快速加载目录的解决方案。

can return可以返回

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

It has callback which will be called when the file is changed.它具有callback ,当文件更改时将调用该callback

It handles situations where files are large enough that watch gets called before they're done writing.它处理文件足够大以至于在完成写入之前调用watch情况。

I've been using it in projects for a year or so, and just recently added promises to it.我已经在项目中使用它一年左右,最近才向它添加了 promise。

Help me battle test it!帮我实战测试吧!

https://github.com/danschumann/loaddir https://github.com/danschumann/loaddir

You can use auto-reload to reload the module without shutdown the server.您可以使用自动重新加载来重新加载模块而无需关闭服务器。

install安装

npm install auto-reload

example例子

data.json数据.json

{ "name" : "Alan" }

test.js测试.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);

Result:结果:

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

another simple solution is to use fs.readFile instead of using require you can save a text file contaning a json object, and create a interval on the server to reload this object.另一个简单的解决方案是使用 fs.readFile 而不是使用 require你可以保存一个包含 json 对象的文本文件,并在服务器上创建一个间隔来重新加载这个对象。

pros:优点:

  • no need to use external libs无需使用外部库
  • relevant for production (reloading config file on change)与生产相关(更改时重新加载配置文件)
  • easy to implement易于实施

cons:缺点:

  • you can't reload a module - just a json containing key-value data你不能重新加载一个模块 - 只是一个包含键值数据的 json

For people using Vagrant and PHPStorm, file watcher is a faster approach对于使用 Vagrant 和 PHPStorm 的人来说, 文件观察器是一种更快的方法

  • disable immediate sync of the files so you run the command only on save then create a scope for the *.js files and working directories and add this command禁用文件的立即同步,以便您仅在保存时运行该命令,然后为 *.js 文件和工作目录创建一个范围并添加此命令

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

where forever.sh is like永远.sh就像

#!/bin/bash

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

I recently came to this question because the usual suspects were not working with linked packages.我最近遇到了这个问题,因为通常的嫌疑人没有使用链接的包。 If you're like me and are taking advantage of npm link during development to effectively work on a project that is made up of many packages, it's important that changes that occur in dependencies trigger a reload as well.如果您像我一样在开发过程中利用npm link有效npm link理由许多包组成的项目,那么依赖项中发生的更改也会触发重新加载,这一点很重要。

After having tried node-mon and pm2, even following their instructions for additionally watching the node_modules folder, they still did not pick up changes.在尝试了 node-mon 和 pm2 之后,即使按照他们的指示额外查看 node_modules 文件夹,他们仍然没有发现更改。 Although there are some custom solutions in the answers here, for something like this, a separate package is cleaner.虽然这里的答案中有一些自定义解决方案,但对于这样的事情,单独的包更干净。 I came across node-dev today and it works perfectly without any options or configuration.我今天遇到了node-dev ,它在没有任何选项或配置的情况下完美运行。

From the Readme:来自自述文件:

In contrast to tools like supervisor or nodemon it doesn't scan the filesystem for files to be watched.与 supervisor 或 nodemon 等工具相比,它不会扫描文件系统以查找要监视的文件。 Instead it hooks into Node's require() function to watch only the files that have been actually required.相反,它挂钩到 Node 的 require() 函数,以仅查看实际需要的文件。

You can do it with browser-refresh .您可以使用browser-refresh 来完成 Your node app restarts automatically, your result page in browser also refreshes automatically.您的节点应用程序会自动重新启动,浏览器中的结果页面也会自动刷新。 Downside is that you have to put js snippet on generated page.缺点是您必须将 js 片段放在生成的页面上。 Here's the repo for the working example.这是工作示例的回购

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

});

I have tried pm2 : installation is easy and easy to use too;我试过pm2 :安装也很简单,也很容易使用; the result is satisfying.结果令人满意。 However, we have to take care of which edition of pm2 that we want.但是,我们必须注意我们想要的 pm2 版本。 pm 2 runtime is the free edition, whereas pm2 plus and pm2 enterprise are not free. pm 2 runtime 是免费版,而 pm2 plus 和 pm2 Enterprise 不是免费版。

As for Strongloop , my installation failed or was not complete, so I couldn't use it.至于Strongloop ,我的安装失败或未完成,所以我无法使用它。

If your talking about server side NodeJS hot-reloading, lets say you wish to have an Javascript file on the server which has an express route described and you want this Javascript file to hot reload rather than the server re-starting on file change then razzle can do that.如果你在谈论服务器端 NodeJS 热重载,假设你希望在服务器上有一个 Javascript 文件,它描述了一个快速路由,并且你希望这个 Javascript 文件热重载而不是服务器在文件更改时重新启动然后razzle可以这样做。

An example of this is basic-server一个例子是基本服务器

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

The file https://github.com/jaredpalmer/razzle/blob/master/examples/basic-server/src/server.js will hot-reload if it is changed and saved, the server does not re-start.文件https://github.com/jaredpalmer/razzle/blob/master/examples/basic-server/src/server.js如果更改并保存将热重载,服务器不会重新启动。

This means you can program a REST server which can hot-reload using this razzle.这意味着您可以编写可以使用此 razzle 进行热重载的 REST 服务器。

it's quite simple to just do this yourself without any dependency... the built in file watcher have matured enough that it dose not sucks as much as before自己做这件事很简单,没有任何依赖......内置的文件观察器已经足够成熟,它不会像以前那样糟糕

you don't need any complicated child process to spawn/kill & pipe std to in/out... you just need a simple web worker, that's all.您不需要任何复杂的子进程来生成/杀死和 pipe std 输入/输出......您只需要一个简单的 web 工作人员,仅此而已。 A web Worker is also what i would have used in browsers too... so stick to web techniques! web Worker 也是我在浏览器中使用的...所以坚持 web 技术! worker will also log to the console 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) {
    change.filename.endsWith('.js') {
      worker.terminate()
      worker = new Worker('./app.js')
    }
  }
}

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

this might not be the best solution where you use anything else other than javascript and do not depend on some build process.这可能不是您使用除 javascript 以外的任何其他东西并且不依赖于某些构建过程的最佳解决方案。

Nowadays WebPack dev server with hot option is used.现在使用带有热选项的 WebPack 开发服务器。 you can add a script like this in your package.json : "hot": "cross-env NODE_ENV=development webpack-dev-server --hot --inline --watch-poll",您可以在 package.json 中添加这样的脚本: "hot": "cross-env NODE_ENV=development webpack-dev-server --hot --inline --watch-poll",

and every change in your files will trigger a recompile automatically并且文件中的每个更改都会自动触发重新编译

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM