如何为我的Node.js服务器添加实时重新加载功能?

41

这是我如何运行我的 Node.js 服务器。当我对前端代码进行更改时,我需要实时重新加载我的服务器。


"start": "node server.js"

浏览器刷新和nodemon可以同时用于此。 - Arpit Solanki
1
我该如何在我的代码中集成它们?我只需要修改package.json文件还是需要在服务器上添加一些代码? - Rebai Ahmed
不需要向服务器添加任何代码。只需使用nodemon来运行您的服务器。 - Arpit Solanki
nodemon看起来适合后端(node服务器)开发。对于前端,您可以结合https://www.npmjs.com/package/watch-run使用https://www.npmjs.com/package/livereload。 - pawel
10个回答

29

首先:

npm install -g nodemon

接下来在你的package.json文件中添加一行脚本代码

"live": "nodemon server.js" 

现在当你运行npm live时,它将实现页面自动刷新

更多详情请参见https://github.com/remy/nodemon

更新:如果还需要页面自动刷新,请执行相应的更新

npm install -g livereload
livereload . -w 1000 -d

欲了解更多详情,请参见https://github.com/napcs/node-livereload


40
这并不会实时刷新浏览器,它只是实时重新加载服务器。您仍然需要手动刷新页面。 - Daniel
8
问题是“我需要实时重新加载我的服务器”,而不是实时重新加载我的浏览器。 - Mark Essel
4
有人寻求真正的实时重新加载功能,这实际上不是服务器的实时重新加载,而是自动重启,这是完全不同的事情。该解决方案将终止Node进程,然后启动一个“新”的进程,该进程恰好在相同的端口上运行。如果某人已登录服务器,或者服务器本身已经通过某些外部API进行了验证,那么此解决方案将无法提供您正在寻找的实时重新加载功能。 - Mike 'Pomax' Kamermans
2
提问者提到他需要前端开发人员。对于初学者来说,这种困惑似乎是合理的。 - GBMan
@dspacejs,你的评论现在已经误导了,因为Mark已经更新了livereload。此外,浏览器的实时重新加载并不是Mark所要求的。 - Timo
显示剩余2条评论

17

重启服务器和刷新浏览器是两回事。我使用nodemon来监控服务器,nodemon可以检测到任何类型文件的更改。但是nodemon无法刷新浏览器页面。所以我使用browser sync来做这件事。

我在gulp中同时使用了两者。

所以,为使其正常工作,需要在package.json中添加依赖项:

"devDependencies": {
"browser-sync": "^2.24.5",
"gulp": "^3.9.1",
"gulp-nodemon": "^2.2.1"
}

在服务器文件中(我的服务器文件位于./bin/www,你的可能位于server.js、app.js或其他位置),express 服务器监听端口3001。

var port = normalizePort(process.env.PORT || '3001');
var server = http.createServer(app);
server.listen(port);

接下来需要在gulp中运行nodemon和browser sync。gulpfile.js的完整内容:

var gulp = require('gulp');
var nodemon = require('gulp-nodemon');
var browserSync = require('browser-sync').create();

gulp.task('gulp_nodemon', function() {
  nodemon({
    script: './bin/www', //this is where my express server is
    ext: 'js html css', //nodemon watches *.js, *.html and *.css files
    env: { 'NODE_ENV': 'development' }
  });
});

gulp.task('sync', function() {
  browserSync.init({
    port: 3002, //this can be any port, it will show our app
    proxy: 'http://localhost:3001/', //this is the port where express server works
    ui: { port: 3003 }, //UI, can be any port
    reloadDelay: 1000 //Important, otherwise syncing will not work
  });
  gulp.watch(['./**/*.js', './**/*.html', './**/*.css']).on("change", browserSync.reload);
});

gulp.task('default', ['gulp_nodemon', 'sync']);

在终端中运行gulp时,它将开始监视服务器并在任何文件更改时刷新浏览器。

尽管我们在express服务器中指定了端口3001,但我们的应用程序将在端口3002上运行,因为我们在browser-sync中编写了端口3002。 3001将被用作代理。


2
我似乎无法在最新的gulp v4中使其工作,尽管在gulp v3中它运行良好。你能建议需要更新/更改什么吗? - Mike D
@MikeD 对于 v4 及以上版本,您需要将最后一行更改为 gulp.task('default', gulp.series('gulp_nodemon', 'sync')); - kohane15
不起作用。尽管您的评论说应用程序将在端口3002上可见,但事实并非如此。在终端上运行“gulp”会打印“listening on *:3001”,这是唯一可以访问应用程序的端口。Nodemon更新文件,但没有浏览器刷新。 - john
2
我已经使用这里的注释来制作一些样板,以防您想要一些可以立即使用的东西,代码在这里。额外的好处是,它也可以准备好使用sass。它使用nodemon、gulp和browsersync,但更新为Gulp 4。除了最后一行之外,大部分与上面的代码相同:exports.build = gulp.parallel(["gulp_nodemon", "sync"]);编写exports.build可以在npm脚本中提供“gulp build”命令。 - Dan Engel

11

使用“livereload”、“connect-livereload”和“nodemon”包,您可以将前端和后端更改实时加载到浏览器中。这样您就不需要使用Gulp。以下是这些包的合作方式:

  • livereload打开一个高端口并通知浏览器已更改的公共文件
  • connect-livereload用一小段代码片段来支持每个服务的HTML页面连接到此高端口
  • nodemon在更改后端文件时重新启动服务器

在Express中设置livereload

设置Express同时启动livereload服务器以监视public目录并在nodemon引起的重启期间与浏览器进行通信:

const livereload = require("livereload");
const connectLivereload = require("connect-livereload");

// open livereload high port and start to watch public directory for changes
const liveReloadServer = livereload.createServer();
liveReloadServer.watch(path.join(__dirname, 'public'));

// ping browser on Express boot, once browser has reconnected and handshaken
liveReloadServer.server.once("connection", () => {
  setTimeout(() => {
    liveReloadServer.refresh("/");
  }, 100);
});

const app = express();

// monkey patch every served HTML so they know of changes
app.use(connectLivereload());

使用nodemon启动Express

使用nodemon启动服务器,例如使用一个专门的watch脚本npm run watch

关键点是要忽略已经被livereload监视的public目录。您还可以配置非默认扩展名的文件,如pug和mustache进行监视。

"scripts": {
  "start": "node ./bin/www",
  "watch": "nodemon --ext js,pug --ignore public"
},

你可以在"使用Express、LiveReload和Nodemon使前端和后端变化实时呈现在浏览器中"中阅读更长的解释。


你好,谢谢你的回答,但是...当我使用“path”时出现了一个错误。
ReferenceError: path is not defined
LiveReload 是如何启动的?
- GBMan
@GBMan path 是一个 Node 核心模块,你可以使用 const path = require("path") 来引入它。很多时候,这已经包含在应用程序设置中处理路径的过程中了。 - pspi
如果您手动设置服务器而不是使用express-generator等工具,则可能无法正常工作。 - Muhammad Saquib Shaikh
@pspi,是否可以将3000端口同时分配给实时重新加载和节点服务器? - K.Raj.

6
npm install browser-refresh -g

并添加你的主要js文件

 if (process.send) {
     process.send('online');
 }

例如
app.listen(port, function() {
    console.log('Listening on port %d', port);

    if (process.send) {
        process.send('online');
    }
});

在body结束标签之前添加您的索引页面。
<script src="{process.env.BROWSER_REFRESH_URL}"></script>

并在终端上启动您的服务器,而不是使用node server.js。
browser-refresh server.js

1
browser-refresh非常棒。运行良好。如果您正在寻找具有SSR的解决方案,请参考:https://medium.com/@gagan_goku/hot-reloading-a-react-app-with-ssr-eb216b5464f1 - Kira
Doks - Timo

4

我的设置中有一个例子:

livereload.js(也就是您的server.js,当然只使用与livereload相关的部分,无需替换您的开发服务器)

const path = require('path');
const fs = require('fs');

const livereload = require('livereload');
const lrserver = livereload.createServer();

const compiled = path.join( __dirname, "dist");
lrserver.watch( compiled ); 

const connect = require('connect');
const stat = require('serve-static');

const server = connect();
server.use( stat( compiled ));

server.listen( 3033 );

console.log( 'Dev server on localhost:3033' );

实际上,它会在本地主机上启动两个服务器:监听:35729的livereload服务器和监听:3033的静态文件服务器。

Livereload观察包含编译后文件(js、css、html)的dist目录。您需要将以下片段添加到每个应该重新加载的HTML页面中:

<script>
 document.write('<script src="http://' + (location.host || 'localhost').split(':')[0] +
                ':35729/livereload.js?snipver=1"></' + 'script>');
</script>

如果您不对js/css/html代码进行转换/编译/预处理(即直接编辑服务的文件),那么请观察源目录就可以了。否则,您需要一个任务来监视源目录的更改并编译到被livereload监视的dist目录中 :) package.json中相关部分:
"scripts": {
    "build": "npm run build:js && npm run build:css",
    "prewatch": "node livereload.js &",
    "watch": "node ./node_modules/watch-run/bin/watch -p './src/**' npm run build",
  },
"devDependencies": {
    "connect": "^3.6.2",
    "livereload": "^0.6.2",
    "serve-static": "^1.12.3",
    "watch-run": "^1.2.5"
  }

$ npm run watch 命令用于构建项目并启动livereload和静态文件服务器。(为了简洁起见,省略了build:*任务)。


2

使用Node.js 19,您可以通过--watch选项监控文件更改。文件更改后,进程会自动重新启动,反映新的更改。

"start": "node --watch server.js"

1
如果使用 grunt,则有一个名为 grunt-contrib-watch 的 npm 包可用于实时重新加载。
另外还有一个名为 grunt-express-server 的包可以与其配合使用。

1

使用名为livereload的npm包。

nodemon一起使用,以便客户端和服务器端都能无缝运行。

npm install livereload nodemon --save

--save-dev。我知道,我知道!

添加浏览器扩展程序。适用于Safari、Firefox和Google Chrome。 在这里获取它们。

确保将此脚本放在package.json中。

  "scripts": {
"start": "nodemon server.js && livereload"

}

server.js是我的入口点。

server.js中添加以下内容:

const livereload = require('livereload');
const reload = livereload.createServer();
reload.watch(__dirname + "/server.js");

server.js 是我想要实现浏览器自动刷新的文件。你也可以添加任意目录,而不仅仅是一个文件。

reload.watch(__dirname + "/public");

在终端中输入:npm start 点击浏览器中的扩展图标进行连接。 你也可以在不同的终端中分别使用livereload和nodemon。
"scripts": {
    "start": "nodemon server.js",
    "livereload": "livereload"
  }

npm start

npm livereload

如果默认端口已被使用,可以使用npm livereload -p PORT_NUMBER

更新:有时保存后无法立即生效。多按几次Ctrl+S重新加载即可使更改生效。我不知道这是浏览器缓存问题还是软件包问题。


1

你可以使用nodemon
它会监视你的项目文件,并在你更改它们时重新启动服务器。

你可以全局安装它:

npm install -g nodemon

在你的项目目录下运行它

cd ./my-project
nodemon

你也可以将它添加到项目的开发依赖中,并从npm脚本中使用:

npm install --save-dev nodemon

然后在你的package.json中添加一个简单的脚本:
"scripts": {
    "start": "node server.js",
    "dev": "nodemon"
}

然后您可以简单地运行以下命令:

npm run dev

8
这如何重新加载浏览器? - Angel S. Moreno
它不会。请参见@Alonad的评论。 - yuval.bl

0
一个非常简单的让浏览器在更改时重新加载的方法是使用react-dev-utils包(https://github.com/facebook/create-react-app/blob/main/packages/react-dev-utils/openBrowser.js
  1. 使用类似nodemon的工具来重建你的服务器。
  2. 在你的express服务器监听回调中调用react-dev-utils
import openBrowser from "react-dev-utils/openBrowser";
import express from "express";

const app = express();
app.get("/foo", (req, res) => res.send("hello: " + new Date().toISOString()));

app.listen(3000, () => {
  console.debug(`Running on http://localhost:3000`);
  
  // this will open a new browser tab  or reload the open one
  openBrowser(`http://localhost:3000`);
});


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接