2

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'
  ]
razorbeard
  • 2,924
  • 1
  • 22
  • 29

4 Answers4

3

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.

Ben
  • 10,106
  • 3
  • 40
  • 58
  • I'm not sure how this plugin is supposed to be used, I see example code but not anything that makes sense in my scenario. Since `livereload` is run by `grunt-contrib-watch`, how would I use `rerun` to handle that? Also, I'm a little put off by the fact that the project's README states it is experimental and it hasn't been maintained in the last 7 months... I think I might have to use two terminal tabs (I use ConEMu running Git Bash on windows) but I wanted to avoid that... And I'm aware of the stigma on CoffeeScript but since this is a config file I didn't think it'd be an issue – razorbeard Oct 18 '13 at 20:35
  • What's wrong with using two Terminal tabs (or three, or four?) If you cannot get this to work using one tab and the gruntplugin I have suggested, then use two tabs. I wouldn't waste your time trying to come up with some elaborate solution to save you having to open up another tab, that seems like more time than it's worth to be honest. You have a third option which is just to forego the livereload option entirely and hit F5 in your browser. Personally I would just use two tabs. – Ben Oct 18 '13 at 21:10
  • Just to see if I could make things simpler. But I tried the two terminal tabs thing and it actually doesn't work any differently. It still doesn't restart the server in time, and I've tried delaying livereload using the `debounceDelay` option and it doesn't delay anything at all. LiveReload occurs as soon as I change the file (which is nice, but it'd be awesome to delay it for server-side stuff to give the server time to restart) – razorbeard Oct 18 '13 at 21:19
  • Right, I see. This isn't a trivial problem to fix then; you might have to look into creating your own plugin to achieve this functionality, or forking `grunt-contrib-watch` to fire an event that you can hook into *before* the watch tasks run as you describe. I just had a quick browse of npm and you have `grunt-wait` too: insert a delay into the watch task while nodemon restarts. Might take a little trial and error to get it working but this may be the best compromise. :) https://npmjs.org/package/grunt-wait – Ben Oct 18 '13 at 21:44
  • Can you use nodemon and livereload events to get a refresh to always follow a restart? – Ian Warburton Dec 07 '14 at 11:47
  • 1
    @IanWarburton - I prefer just having a long running process. You can achieve it on the command line directly by appending `&` to the end of the command, that way you 'free up' your shell to do some other task without having to have a window open. The way I would do this today would probably involve having nodemon or some other server spawned via node or whatever, background it, then develop and not have to worry about managing the server restart. Think that'd be a faster workflow, too. See more on this here: https://kb.iu.edu/d/afnz – Ben Dec 07 '14 at 13:38
  • @Ben I'm not following. Please see my answer to see what I'm going on about. – Ian Warburton Dec 08 '14 at 18:14
  • @IanWarburton Your use case is more for gulp, correct? I think if you are having problems with that setup then post it as a separate question. :-) – Ben Dec 08 '14 at 20:55
  • @Ben Grunt/Gulp it doesn't make any difference. In both cases your watch needs to fire at the correct time. – Ian Warburton Dec 08 '14 at 22:08
  • @IanWarburton I think if you need to have that specific ordering then you need to have a script that both manages the server and the watch task. So that when you receive a change on disk, then you can shut down the server, relaunch it, and then run your live reload script. Still seems like a hacky way to develop, though. – Ben Dec 08 '14 at 22:38
  • @ben I want to run nodemon with Webstorm so a script is out as far as I know. Hacky yes but it's very simple and it works. – Ian Warburton Dec 08 '14 at 22:48
  • @Ben in fact I take that back. Webstorm's big play button can be hooked up to multiple types of run configurations do maybe I can do this just using scripts. – Ian Warburton Dec 08 '14 at 23:55
  • @IanWarburton LGTM. :-) – Ben Dec 09 '14 at 15:02
2

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

```

Amit Portnoy
  • 5,957
  • 2
  • 29
  • 30
1

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

cl0udw4lk3r
  • 2,663
  • 5
  • 26
  • 46
0

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.

Ian Warburton
  • 15,170
  • 23
  • 107
  • 189