Node.js — автоматическое обновление в разработке

Я пытаюсь улучшить опыт разработки в моем Node. Для этого я хочу:

а) перезапустить сервер при изменении кода на стороне сервера
б) обновить браузер при изменении кода на стороне клиента.

В Для этого я начал интегрировать nodemon и browserSync в мой скрипт глотка.

В моем сценарии 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

Я понимаю в какой-то степени. У меня есть app.set('port', process.env.PORT || 3002); в моем файле server.js. Тем не менее, я думал, что это было целью установки значения прокси. Тем не менее, всякий раз, когда я вношу изменения в код, я вижу следующую связанную ошибку в окне консоли:

[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 также использует порт 3001 для пользовательского интерфейса BrowserSync. По этим двум причинам я решил установить порт 3002 в моем файле server.js и создать прокси-сервер, показанный выше. Что я делаю не так?


person JQuery Mobile    schedule 03.03.2016    source источник
comment
'nodemon' stackoverflow .com/questions/24750395/   -  person Robert Rowntree    schedule 06.03.2016
comment
Вы спросили что-то подобное здесь stackoverflow.com/questions/35576663/   -  person Satyajeet    schedule 09.03.2016
comment
Это приложение ExpressJS?   -  person Trevor    schedule 09.03.2016
comment
@три да. это экспресс-приложение   -  person JQuery Mobile    schedule 10.03.2016
comment
какую версию браузера вы используете?   -  person lud1977    schedule 11.03.2016


Ответы (5)


На самом деле вам не нужно использовать gulp, чтобы это работало.

а) перезапустить мой сервер при изменении кода на стороне сервера

Установите nodemon глобально, используя npm i -g nodemon, затем в папке приложения выполните nodemon или nodemon ${index-file-of-your-app}.

б) обновить браузер при изменении кода на стороне клиента.

Используйте браузер или веб-пакет. Я предпочитаю использовать веб-пакет; вам может понадобиться немного узнать о конфигурации, но хорошая вещь с webpack заключается в том, что вам не нужно его обновлять. Как только изменения будут найдены, они автоматически отразятся в браузере. https://github.com/webpack/docs/wiki/hot-module-replacement-with-webpack

person mateeyow    schedule 07.03.2016
comment
У меня есть другие вещи в моем файле глотка. Вот почему я хочу это залпом. Есть ли способ сделать это, который соответствует моему вопросу? - person JQuery Mobile; 08.03.2016
comment
Могу ли я увидеть ваш файл gulp или список процессов/шагов при запуске gulp? - person mateeyow; 08.03.2016

Вы можете перезагружать в браузере как внешние, так и внутренние изменения, используя вместе пакеты «livereload», «connect-livereload» и «nodemon». Кроме того, таким образом вам не нужны Gulp или Grunt. Вот как пакеты работают вместе:

  • livereload открывает высокий порт и уведомляет браузер об измененных общедоступных файлах
  • connect-livereload обезьяна исправляет каждую обслуживаемую HTML-страницу фрагментом, который подключается к этому высокому порту
  • Затем nodemon используется для перезапуска сервера на измененных внутренних файлах.

Настройте livereload в Express

Настройте Express для запуска сервера livereload, наблюдающего за общедоступным каталогом, и проверки связи с браузером во время перезапуска, вызванного 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());

Запустите Express с помощью nodemon

Затем вы запустите сервер с помощью nodemon, например, с выделенным сценарием наблюдения, запустив npm run watch.

Ключевым моментом здесь является игнорирование общедоступного каталога, за которым уже следит livereload. Вы также можете настроить файлы с расширениями не по умолчанию, такими как мопс и усы, для просмотра.

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

Вы можете прочитать более подробное объяснение в "Обновить внешние и внутренние изменения в браузере с Express, LiveReload и Nodemon."

person pspi    schedule 05.03.2020

@mateeyow прав.

Но если вы хотите, чтобы браузер перезагружался автоматически, вам также нужен плагин livereload.

Включить 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,
})];
person Jane    schedule 21.02.2017

Возможно, мне не хватает некоторого контекста (например, я не уверен, что представляет собой 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'));
});
person Trevor    schedule 10.03.2016

Ошибка EADDRINUSE обычно возникает из-за уже открытого соединения на указанном порту. Вероятно, это связано с тем, что предыдущий экземпляр соединения не был правильно закрыт при перезапуске приложения.

Взгляните на эту суть и, в частности, попробуйте что-то подобное в своем файле 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; 
        } 
    });
});
person lud1977    schedule 11.03.2016