gruntjs / grunt-contrib-watch

Run tasks whenever watched files change.
http://gruntjs.com/
MIT License
1.98k stars 356 forks source link

livereload error when running concurrent watch tasks #240

Open colinkahn opened 10 years ago

colinkahn commented 10 years ago

I'm using watch with https://github.com/sindresorhus/grunt-concurrent in a setup that looks sort of like this:

  concurrent:
    development: [
      "watch:coffee"
      "watch:jade"
    ]
  watch:
    options:
      livereload: true
    jade:
      [config for jade...]
    coffee:
      [config for coffee..]

When I run concurrent:development I get the error: "Fatal error: Port 35729 is already in use by another process." It will happen on whatever the second watch task I put in my concurrent task. I'm guessing the first watch task ends up spinning up the livereload server, and then the second one attempts to as well on the same port causing it to fail. Is there a better way to achieve what I'm attempting?

shama commented 10 years ago

Just do grunt watch. The watch task will already watch all targets in your watch config concurrently and then only run the tasks configured for the corresponding files.

colinkahn commented 10 years ago

That does work, but I forgot to mention that I have another watch task that I don't want to always run (one for end to end testing). So, I specifically want to just run only a couple of the defined watch tasks.

  concurrent:
    development: [
      "watch:coffee"
      "watch:jade"
    ]
  watch:
    options:
      livereload: true
    jade:
      [config for jade...]
    coffee:
      [config for coffee..]
    e2e:
      [config for e2e, watches some files that coffee watches already...]
dcholth commented 10 years ago

@colinkahn Did you ever find a work around? Trying to do exactly the same thing - different group of watches for when running tests.

fredericgrati commented 10 years ago

Also trying to do the same thing... :) @colinkahn , @colinkahn, have you find a solution ?

shama commented 10 years ago

You can do a dynamic alias task:

// Run with: grunt switchwatch:target1:target2 to only watch those targets
grunt.registerTask('switchwatch', function() {
  var targets = Array.prototype.slice.call(arguments, 0);
  Object.keys(grunt.config('watch')).filter(function(target) {
    return !(grunt.util._.indexOf(targets, target) !== -1);
  }).forEach(function(target) {
    grunt.log.writeln('Ignoring ' + target + '...');
    grunt.config(['watch', target], {files: []});
  });
  grunt.task.run('watch');
});

It might be worth adding this feature to the watch itself. atm it takes in only a single target where it could accept an array as well.

fredericgrati commented 10 years ago

Works great :) Thx @shama !!

+1 to adding this feature into watch itself.

vkadam commented 10 years ago

I am able to get it working using watch task inbuilt configuration. Instead of

livereload:true

do

livereload:12345

Read https://github.com/gruntjs/grunt-contrib-watch#optionslivereload

seglo commented 10 years ago

I get the same error "Fatal error: Port 35729 is already in use by another process." when I try to use grunt-contrib-watch in conjunction with grunt-express or grunt-express-server. I'm trying to run the express server on a different port for mocking out the backend. I don't have any livereload options enabled for the express server, yet I get this error whenever I enable livereload in grunt-contrib-watch on its default port.

shama commented 10 years ago

@seglo What does your config look like? 35729 is a fairly unique port so I suspect you have multiple watch task targets starting livereload servers (or maybe another tab running grunt watch?)

seglo commented 10 years ago

@shama I made sure I have no other tabs or processes running on that port. It has to be some kind of conflicting config in my grunt file. My grunt file is pretty large.. it's basically the grunt file the yeoman generator-angular creates. Here are my watch and express configs (based on the yo-angular template config):

    // The actual grunt server settings
    connect: {
      options: {
        port: 9000,
        // Change this to '0.0.0.0' to access the server from outside.
        hostname: 'localhost',
        //livereload: 35729
      },
      livereload: {
        options: {
          open: true,
          base: [
            '.tmp',
            '<%= yeoman.app %>'
          ]
        }
      },
      test: {
        options: {
          port: 9001,
          base: [
            '.tmp',
            'test',
            '<%= yeoman.app %>'
          ]
        }
      },
      dist: {
        options: {
          base: '<%= yeoman.dist %>'
        }
      }
    },
...
    // Watches files for changes and runs tasks based on the changed files
    watch: {
      js: {
        files: ['<%= yeoman.app %>/scripts/{,*/}*.js'],
        tasks: ['newer:jshint:all'],
        options: {
          livereload: true /* when I set this to a port like "12345" I can run concurrently, but when it's set to true I get the error */
        }
      },
      jsTest: {
        files: ['test/spec/{,*/}*.js'],
        tasks: ['newer:jshint:test', 'karma']
      },
      styles: {
        files: ['<%= yeoman.app %>/styles/{,*/}*.css'],
        tasks: ['newer:copy:styles', 'autoprefixer']
      },
      gruntfile: {
        files: ['Gruntfile.js']
      },
      livereload: {
        options: {
          livereload: '<%= connect.options.livereload %>'
        },
        files: [
          '<%= yeoman.app %>/{,*/}*.html',
          '.tmp/styles/{,*/}*.css',
          '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
        ]
      }
    },
...
    express : {
      mockApi: {
        options: {
          server: path.resolve('./mock-api.js'),
          port: 3000
        }
      }
    },

EDIT: Added connect config for reference.

shama commented 10 years ago

@seglo The problem is this: livereload: '<%= connect.options.livereload %>' points to a non-existent place in the config (because it is commented out above). So the watch task will use the default settings and start up a live reload server on 35729.

I'm not sure why they have livereload configured within the watch:js and watch:livereload. It only needs to be configured once. I would remove watch.js.options and just let the watch:livereload target handle which files trigger it. Then if commenting out //livereload: 35729 be sure to update livereload: '<%= connect.options.livereload %>' to point to something.

fad12 commented 10 years ago

Run this command : $ lsof | grep 35729 see what other app useing the same port 1- make sure you have only on terminal window open 2 - if you install the live reload to sublime text just change the port

mightyiam commented 9 years ago

I remember dealing with this. Here's how I solved it.

SamStonehouse commented 7 years ago

I came across this issue when I was trying to solve a similar problem; the solution I opted for was to have a separate watch task to watch the built files and only trigger livereload on that, it didn't occur to me to do that until I read through all the docs so leaving this here hoping it's useful to someone else too.

  grunt.initConfig({
      'scripts-app': {
        files: ['source/scripts/**/*.js'],
        tasks: ['lint', 'scripts'],
        options: {
          spawn: false,
        },
      },
      assets: {
        files: ['source/assets/**/*'],
        tasks: ['assets'],
        options: {
          spawn: false,
        },
      },
      html: {
        files: ['source/html/**/*'],
        tasks: ['template'],
        options: {
          spawn: false,
        },
      },
      livereload: {
        options: { livereload: true },
        files: ['public/**/*'],
      },
    },
    concurrent: {
      watch: {
        tasks: ['watch:scripts', 'watch:assets', 'watch:html', 'watch:livereload'],
        options: {
          logConcurrentOutput: true,
        },
      },
    },
  });