Grunt: `contrib-watch` Fire livereload event after `grunt-nodemon` has restarted when server-side `.coffee` files are compiled

StackOverflow https://stackoverflow.com/questions/19457002

Question

I've been having an issue with Grunt.js and a few plugins, notably: grunt-contrib-watch, grunt-nodemon and grunt-contrib-coffee. I've been trying to figure this out for two days now but I don't think my knowledge of Grunt is sufficient to solve it at this point.

The problem I'm experiencing is simply that I want my server-side .coffee files to compile and then have nodemon restart the server and THEN only have livereload work. Right now, Livereload works as intended for everything but server-side coffee files. contrib-watch detects the change, runs coffee and fires off a livereload event, but then nodemon restarts.

Is there a way to get nodemon to restart before the page reloads so that what I see on the screen is up-to-date with what's going on in my server-side code?

I've been presented with the option of just running nodemon in a separate terminal tab, but I'm on Windows and would much prefer to keep one terminal running for this purpose and is the whole reason I'm using grunt-concurrent.

Here's my Gruntfile, it's quite early in it's stages (as I try to figure all this out). If you would prefer I compile it to JavaScript, then just leave a comment and request so, I will be happy to.

module.exports = (grunt) ->

  # configuration
  grunt.initConfig
    pkg: grunt.file.readJSON 'package.json'

    # watch task
    watch:
      css:
        files: ['src/assets/styles/**/*.styl']
        tasks: ['stylus']
        options:
          livereload: true
      coffee:
        files: ['src/**/*.coffee']
        tasks: ['coffee']
      js:
        files: ['**/*.js']
        options:
          livereload: true
      jade:
        files: ['views/**/*.jade']
        options:
          livereload: true

    # compile coffeescript to javascript
    coffee:
      compile:
        options:
          sourceMap: true
        files: [
          expand: true
          cwd: 'src/'
          src: ['**/*.coffee']
          dest: ''
          ext: '.js'
        ]

    # compile stylus to css
    stylus:
      compile:
        files: [
          expand: true
          cwd: 'src/assets/styles/'
          src: ['**/*.styl']
          dest: 'assets/styles/'
          ext: '.css'
        ]

    # run server
    nodemon:
      dev:
        options:
          file: 'server.js'
          watchedExtensions: ['js', 'json']
          ignoredFiles: [
            'assets/**',
            'node_modules/**',
            '**/.js.map'
          ]

    # run tasks concurrently for fast builds
    concurrent:
      first:
        tasks: ['coffee', 'stylus']
        options:
          logConcurrentOutput: true
      second:
        tasks: ['nodemon', 'watch']
        options:
          logConcurrentOutput: true

  # load dependencies
  require('load-grunt-tasks') grunt

  # register tasks
  grunt.registerTask 'default', [
    'concurrent:first',
    'concurrent:second'
  ]
Était-ce utile?

La solution

I've not used this myself but I came across it a while ago: grunt-rerun. Used in combination with a watch task you can pause a long running task such as express (but probably would work with nodemon as well), run some tasks, then start the task again. The sample config looks like so:

grunt.initConfig({
  watch: {
      dev: {
        files: ['server/*.js'],

        //Note the :go flag used for sending the reload message to the rerun server
        tasks: ['clean','rerun:dev:express:go']
      },
    },
    express: {
        dev: {
            options: {
                port: 3000,
                bases: ['/public'],
                keepalive: true,
                server: path.resolve('./server/app.js')
            }
        }
    },
    // Configuration to be run (and then tested).
    rerun: {
      dev: {
        options: {
          tasks: ['express']
        },
      },
    }
})

https://npmjs.org/package/grunt-rerun

I'm not entirely sure about the live reload thing. My guess would be because it shuts down the process, by spawning a new one it would load the page afresh, but I haven't used this personally so I'm not sure.

The second alternative is yes, to use a command prompt that supports multiple tabs, such as Console. I'm a Mac user and so I use iTerm 2 which has multiple panes; most of the time I have four open per project, for watch, testem, a php server and a shell for everything else. You may find that this is a lot quicker and a lot less hassle.

Just a quick note on Coffeescript, a lot of JavaScript developers don't use it, so to get a wider audience to understand your source code, it may be good practice to compile coffee into js before you post your question.

Autres conseils

I used watch for watching server files and a simple '2SecDelay' task that gives nodemon time to restart the server.

So, I got a patch, but it's ugly:

grunt.registerTask '2SecDelay', 'just taking some time', ->
  done = @async()
  setTimeout((() -> done()), 2000)

...

nodemon:
  server:
    ... run server and watch server related files ...
watch:
  server: 
    files: ... same files as the nodemon watches ...
    tasks: ['2SecDelay']
concurrent:
  server:
    ['nodemon', 'watch']

```

Why should you livereloading the coffee/stylus/jade files?

Just livereload the compiled changes instead! I guess you have a public folder with the compiled output from your .coffee/.styl/.jade files

This is my Gruntfile example:

module.exports = (grunt) ->
  grunt.config.init
    ...

    watch:
      css:
        files: ['src/assets/styles/**/*.styl']
        tasks: ['stylus']
      coffee:
        files: ['src/**/*.coffee']
        tasks: ['coffee']
      jade:
        files: ['views/**/*.jade']
      livereload:
        files: ['public/**/*.*']
        options:
          livereload: true
    ...

This way you will also trigger livereloading for non js/css file changes, like images, fonts, and so on. And you are always sure that livereload will be triggered

I added the following http request to tiny-lr when my server starts.

var server = app.listen(process.env.PORT || 3000, function() {
  debug('Koa server listening on port ' + server.address().port);

  require('http').get({host: 'localhost', port: 35729, path: '/changed?files=app.js'},      
     function (response){
        console.log('Restart');
  });
});

I have Webstorm running nodemon so this seems like an easy way to communicate between nodemon and the livereload server implementation that I'm using.

I tried running nodemon from a Gulp task and having the http call there in order to keep my code clean but nodemon doesn't seem to have an event that fires after the server has started - its 'restart' event fires before the restart.

The app's own listen event seems to be the best place to trigger a refresh as you that know at that point the server is ready to start handling requests.

These aren't the technologies specified in the question but the principle should be applicable just the same.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top