Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I use grunt-contrib-watch and grunt-contrib-coffee to compile CoffeeScript only as needed?

I'd like to run coffee lint and coffee compile on only the single file that I'm saving. There are hundreds of CoffeeScript files in my project, and compiling all of them takes too much time.

Here's my Gruntfile:

module.exports = (grunt) ->

  grunt.initConfig

    pkg: grunt.file.readJSON 'package.json'

    coffee:
      all:
        expand: true
        bare: true
        cwd: 'src/coffeescript/'
        src: '**/*.coffee'
        dest: 'public/js/compiled'
        ext: '.js'

    coffeelint:
      all: ['src/coffeescript/**/*.coffee']

    watch:
      coffeescript:
        files: ['src/**/*.coffee']
        tasks: ['coffeelint', 'coffee']
        options:
          spawn: false

  grunt.event.on 'watch', (action, filepath) ->
    grunt.config(['coffeelint', 'all'], filepath)
    grunt.config(['coffee', 'all'], filepath)

  grunt.loadNpmTasks 'grunt-coffeelint'
  grunt.loadNpmTasks 'grunt-contrib-coffee'
  grunt.loadNpmTasks 'grunt-contrib-watch'

  grunt.registerTask 'default', ['coffeelint', 'coffee', 'watch']

The coffeelint task runs successfully only on the changed file.

The coffee compilation doesn't produce any JS files, even though grunt says it runs.

Here's the output after saving a single coffee file:

OK
>> File "src/coffeescript/app.coffee" changed.


Running "coffeelint:all" (coffeelint) task
>> 1 file lint free.

Running "coffee:all" (coffee) task

Running "watch" task
Completed in 0.009s at Sat Feb 01 2014 13:10:07 GMT-0600 (CST) - Waiting...

What's wrong here? Any help would be greatly appreciated!

Update:

Here's a working example:

module.exports = (grunt) ->

  fs = require 'fs'
  isModified = (filepath) ->
    now = new Date()
    modified =  fs.statSync(filepath).mtime
    return (now - modified) < 10000

  grunt.initConfig

    coffee:
      options:
        sourceMap: true
        bare: true
        force: true # needs to be added to the plugin
      all:
        expand: true
        cwd: 'src/coffeescript/'
        src: '**/*.coffee'
        dest: 'public/js/compiled'
        ext: '.js'
      modified:
        expand: true
        cwd: 'src/coffeescript/'
        src: '**/*.coffee'
        dest: 'public/js/compiled'
        ext: '.js'
        filter: isModified

    coffeelint:
      options:
        force: true
      all:
        expand: true
        cwd: 'src/coffeescript/'
        src: '**/*.coffee'
      modified:
        expand: true
        cwd: 'src/coffeescript/'
        src: '**/*.coffee'
        filter: isModified

    watch:
      coffeescript:
        files: ['src/**/*.coffee']
        tasks: ['coffeelint:modified', 'coffee:modified']

  grunt.loadNpmTasks 'grunt-coffeelint'
  grunt.loadNpmTasks 'grunt-contrib-coffee'
  grunt.loadNpmTasks 'grunt-contrib-watch'

  grunt.registerTask 'default', ['coffeelint:all', 'coffee:all', 'watch']
like image 989
Eric the Red Avatar asked Feb 01 '14 19:02

Eric the Red


2 Answers

You can use grunt-newer to only compile files when the source is newer than its compiled output.

Install it with:

npm install grunt-newer --save-dev

Then change your coffeescript task a bit. If you go to section on "Building the files object dynamically" in the Grunt.js docs you'll see that you need to hold the information related to file location and location of compiled output in a files array for the task to execute correctly.

Additional options, like bare: true, can then be specified with an options object.

So for your coffee task, do this instead:

   coffee:
      all:
        files: [{
          expand: true
          cwd: 'src/coffeescript/'
          src: '**/*.coffee'
          dest: 'public/js/compiled'
          ext: '.js'
        }]
        options:
          bare: true
          spawn: false

then use newer in your watch task like so:

    watch:
      coffeescript:
        files: ['src/**/*.coffee']
        tasks: ['newer:coffeelint:all', 'newer:coffee:all']
        options:
          spawn: false

Newer will then only compile files that are more recent than their compiled versions.

like image 69
agconti Avatar answered Oct 24 '22 21:10

agconti


Try to add something like this to your c task

 coffee:
  all:
    filter: (filepath) ->
        fs = require('fs')
        now = new Date()
        modified =  fs.statSync(filepath).mtime
        return (now - modified) < 10000 # or another difference in millyseconds

Read more in documentation

like image 28
kharandziuk Avatar answered Oct 24 '22 20:10

kharandziuk