Node.js - 开发中的自动刷新

Posted

技术标签:

【中文标题】Node.js - 开发中的自动刷新【英文标题】:Node.js - Auto Refresh In Dev 【发布时间】:2016-06-16 18:20:56 【问题描述】:

我正在尝试改善我的 Node.js 中的 DEV 体验。为此,我想: a) 更改服务器端代码时重新启动我的服务器 b) 当客户端代码发生变化时刷新浏览器。为了实现这一点,我开始将 nodemon 和 browserSync 集成到我的 gulp 脚本中。

在我的 gulp 脚本中,我有以下任务:

gulp.task('startDevEnv', function(done) 
    // Begin watching for server-side file changes
    nodemon(
         script: input.server, ignore:[input.views] )
        .on('start', function () 
            browserSync.init(
                proxy: "http://localhost:3002"
            );
        )
    ;    

    // Begin watching client-side file changes
    gulp.watch([ input.css, input.js, input.html ], function()  browserSync.reload(); );
    done();
);

当上述任务运行时,我的浏览器打开到http://localhost:3000/。我的应用程序按预期可见。但是,在控制台窗口中,我注意到:

Error: listen EADDRINUSE :::3002

我在某种程度上理解。我的 server.js 文件中有app.set('port', process.env.PORT || 3002);。然而,我认为这是设置代理值的目的。尽管如此,每当我更改代码时,我都会在控制台窗口中看到以下相关错误:

[07:08:19] [nodemon] restarting due to changes...
[07:08:19] [nodemon] starting `node ./dist/server.js`
events.js:142
      throw er; // Unhandled 'error' event
      ^

TypeError: args.cb is not a function
    at Object.init (/Users/me/Website/Develop/node_modules/browser-sync/lib/public/init.js:25:25)
    at null.<anonymous> (/Users/me/Website/Develop/gulpfile.js:142:25)
    at emitNone (events.js:73:20)
    at emit (events.js:167:7)
    at Object.run (/Users/me/Website/Develop/node_modules/nodemon/lib/monitor/run.js:97:7)
    at Function.run.kill (/Users/me/Website/Develop/node_modules/nodemon/lib/monitor/run.js:221:7)
    at null.<anonymous> (/Users/me/Website/Develop/node_modules/nodemon/lib/monitor/run.js:333:7)
    at emitOne (events.js:83:20)
    at emit (events.js:170:7)
    at restartBus (/Users/me/Website/Develop/node_modules/nodemon/lib/monitor/watch.js:162:7)
Me-MBP:Develop me$ events.js:142
      throw er; // Unhandled 'error' event
      ^

Error: listen EADDRINUSE :::3002
    at Object.exports._errnoException (util.js:856:11)
    at exports._exceptionWithHostPort (util.js:879:20)
    at Server._listen2 (net.js:1238:14)
    at listen (net.js:1274:10)
    at Server.listen (net.js:1370:5)
    at Object.<anonymous> (/Users/me/Website/Develop/dist/server.js:70:8)
    at Module._compile (module.js:399:26)
    at Object.Module._extensions..js (module.js:406:10)
    at Module.load (module.js:345:32)
    at Function.Module._load (module.js:302:12)

此时,我的代码更改不会出现在我的浏览器中。我不明白我做错了什么。我怀疑我的端口配置错误。但是,我不确定它们应该如何设置。

默认情况下,BrowserSync 使用端口 3000。BrowserSync 还为 BrowserSync UI 使用端口 3001。由于这两个原因,我想我应该在 server.js 文件中将端口设置为 3002 并创建上面显示的代理。我做错了什么?

【问题讨论】:

'nodemon' ***.com/questions/24750395/… 你在这里问过类似的问题***.com/questions/35576663/… 这是一个 ExpressJS 应用程序吗? @threed 是的。这是一个 expressjs 应用程序 您使用的是什么版本的 browsersync? 【参考方案1】:

您可以通过同时使用“livereload”、“connect-livereload”和“nodemon”包将前端和后端更改实时加载到浏览器。此外,这样你就不需要 Gulp 或 Grunt。以下是这些包如何一起发挥作用:

livereload打开高端口,通知浏览器公共文件发生变化 connect-livereload monkey 用连接到这个高端口的 sn-p 修补每个提供的 HTML 页面 nodemon 然后用于在更改的后端文件上重新启动服务器

在 Express 中设置 livereload

将 Express 设置为在 nodemon 引起的重启期间启动 livereload 服务器并查看公共目录并 ping 浏览器:

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 启动服务器,例如,通过运行 npm run watch 使用专用的监视脚本。

这里的关键点是忽略已经被 livereload 监视的公共目录。您还可以配置具有非默认扩展名的文件,例如 pug 和 mustache。

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

您可以在"Refresh front and backend changes to browser with Express, LiveReload and Nodemon."阅读更长的解释

【讨论】:

也不要使用这里提供的命令行,使用已经存在的命令行来执行节点如-r esm index.js 为什么需要connect-livereload,我认为livereload不需要任何“支持包”就可以观看html文件?也许这里需要它,因为您在 server.js 中实现了 livereload 而不是使用 livereload 从 cmd 实现。见docs【参考方案2】:

我可能遗漏了一些上下文(例如,我不确定 input 代表什么),但是,我认为 npm 模块 reload 可能会解决您的问题。这是来自 npm 包页面的示例:

var express = require('express')
  , http = require('http')
  , path = require('path')
  , reload = require('reload')
  , bodyParser = require('body-parser')
  , logger = require('morgan')

var app = express()

var publicDir = path.join(__dirname, '')

app.set('port', process.env.PORT || 3000)
app.use(logger('dev'))
app.use(bodyParser.json()) //parses json, multi-part (file), url-encoded  

app.get('/', function(req, res) 
  res.sendFile(path.join(publicDir, 'index.html'))
)

var server = http.createServer(app)

//reload code here 
//optional reload delay and wait argument can be given to reload, refer to [API](https://github.com/jprichardson/reload#api) below 
reload(server, app, [reloadDelay], [wait])

server.listen(app.get('port'), function()
  console.log("Web server listening on port " + app.get('port'));
);

【讨论】:

【参考方案3】:

@mateeyow 是对的。

但是如果你想让浏览器自动重新加载,你还需要livereload-plugin。

启用 webpack-hot-replacement 只替换浏览器内存中的代码,livereload-plugin 会重新加载它。

以摇滚为例:https://github.com/orange727/rock/blob/master/app/templates/webpack/webpack.make.js#L255

就像:

webpackConfig.plugins: [
  new webpack.HotModuleReplacementPlugin(),
  new LiveReloadPlugin(
    appendScriptTag: true,
    port: config.ports.livereload,
)];

【讨论】:

【参考方案4】:

EADDRINUSE 错误通常是由于指定端口上的连接已打开。这可能是由于之前的连接实例在重新启动应用时未正确关闭。

看看this gist,特别是在你的 gulp 文件中尝试这样的事情:

'use strict';

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

gulp.task('default', ['browser-sync'], function () );

gulp.task('browser-sync', ['nodemon'], function() 
    browserSync.init(null, 
        proxy: "http://localhost:3002"
    );
);

gulp.task('nodemon', function (cb) 

    var started = false;

    return nodemon(
        script: 'app.js'
    ).on('start', function () 
        // to avoid nodemon being started multiple times
        if (!started) 
            cb();
            started = true; 
         
    );
);

【讨论】:

【参考方案5】:

你实际上不需要使用 gulp 来实现它。

a) 更改服务器端代码时重新启动我的服务器

使用npm i -g nodemon 全局安装nodemon,然后在您的应用文件夹上执行nodemonnodemon $index-file-of-your-app

b) 当客户端代码发生变化时刷新浏览器。

使用 browserify 或 webpack。我更喜欢使用 webpack;你可能需要稍微了解一下配置,但是 webpack 的好处是你不需要刷新它。一旦发现更改,更改将自动反映在浏览器上。 https://github.com/webpack/docs/wiki/hot-module-replacement-with-webpack

【讨论】:

我的 gulp 文件中还有其他内容。这就是为什么我想要一饮而尽。有没有与我的问题一致的方法? 我可以查看您的 gulp 文件或列出运行 gulp 时的流程/步骤吗?

以上是关于Node.js - 开发中的自动刷新的主要内容,如果未能解决你的问题,请参考以下文章

使用Spring Boot开发者工具进行自动重启和页面自动刷新

Browsersync结合gulp和nodemon实现express全栈自动刷新

Browsersync 浏览器自动刷新

本地开发中的Angular2慢速自动页面刷新 - Windows

Node.js开发者最常范的10个错误

使用 Python 开发 Flask 应用程序时如何自动刷新浏览器?