Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Grunt: Watch multiple files, Compile only Changed

I'm new to Grunt, and so far I'm enjoying it very much. I want Grunt to compile only the changed files when running grunt watch

In my Grunfile.coffee I currently have (relevant parts).
Note: assets/javascript/app.coffee and assets/javascript/app.js are directories

    coffee:
        default:
            expand: true
            cwd: "assets/javascript/app.coffee"
            src: ["*.coffee"]
            dest: "assets/javascript/app.js"
            ext: ".js"

    uglify:
        dev:
            options:
                beautify: true
                compress: false
                mangle: false
                preserveComments: 'all'

            files: 
                "js/app.js": "assets/javascript/app.js/*.js"
                "js/libs.js": "assets/javascript/libs/*.js"

    watch:
        coffeescript:
            files: 'assets/javascript/**/*.coffee'
            tasks: ["coffee"]

        javascript:
            files: "assets/**/*.js"
            tasks: ["uglify:dev"]
        livereload:
            files: ["Gruntfile.coffee", "js/*.js", "*.php", "css/*.css", "images/**/*.{png,jpg,jpeg,gif,webp,svg}", "js/*.js", ]
            options:
                livereload: true

There is probably a shorter way around, but I'm compiling app.coffee to app.js first, so that after I distribute my work, people who aren't comfortable with Coffeescript can browse the code in somewhat reasonable manner.

The problem with all this is that now that I save a Coffeescript file, I get too many steps ( I think ):

>> File "assets/javascript/app.coffee/browse.coffee" changed.

Running "coffee:default" (coffee) task
File assets/javascript/app.js/browse.js created.
File assets/javascript/app.js/filters.js created.

Done, without errors.
Completed in 0.837s at Tue May 28 2013 12:30:18 GMT+0300 (EEST) - Waiting...
OK
>> File "assets/javascript/app.js/browse.js" changed.
>> File "assets/javascript/app.js/filters.js" changed.

Running "uglify:dev" (uglify) task
File "js/app.js" created.
File "js/libs.js" created.

Done, without errors.
Completed in 0.831s at Tue May 28 2013 12:30:19 GMT+0300 (EEST) - Waiting...
OK
>> File "js/app.js" changed.
>> File "js/libs.js" changed.

Completed in 0.000s at Tue May 28 2013 12:30:19 GMT+0300 (EEST) - Waiting...

Currently I'm just setting up my project, but I will have a lot more Coffeescript files, and I don't want Coffeescript to recompile all of the files, on each file change.

Furthermore, libs.js has no part in all of this at all, but I guess it is still compiled, because it also matches the "assets/*/.js" pattern.

Is there a way to make Grunt compile only the files that have changed ?

like image 932
pyronaur Avatar asked May 28 '13 09:05

pyronaur


People also ask

Is grunt deprecated?

grunt. util. _ is deprecated and we highly encourage you to npm install lodash and var _ = require('lodash') to use lodash .

Is grunt a task runner?

Grunt is a JavaScript task runner, a tool used to automatically perform frequent tasks such as minification, compilation, unit testing, and linting. It uses a command-line interface to run custom tasks defined in a file (known as a Gruntfile). Grunt was created by Ben Alman and is written in Node.

What does grunt build do?

Grunt can perform repetitive tasks very easily, such as compilation, unit testing, minifying files, running tests, etc. Grunt includes built-in tasks that extend the functionality of your plugins and scripts. The ecosystem of Grunt is huge; you can automate anything with very less effort.

What is grunt JS in node JS?

Grunt is a command line Javascript task runner utilizing Node. js platform. It runs custom defined repetitious tasks and manages process automation. The project's homepage lists many big players in software development that use Grunt in their development as part of continuous integration workflow.


3 Answers

I've finally found a real solution! And it's super simple too!

npm install grunt-newer --save-dev

Then in your Gruntfile (after loading the task in grunt):

watch:
    coffeescript:
        files: 'assets/javascript/**/*.coffee'
        tasks: ["newer:coffee"]

And that's it! The Awesome grunt-newer is awesome!

like image 52
pyronaur Avatar answered Oct 31 '22 00:10

pyronaur


If you concat all .coffee sources into one .js file, then you will have to recompile it every time if any of your sources changes. Split it up to several .js files and make a release task where you only concat these .js files. This way you still only need to include one .js file.

See Using gruntjs, how do watch for changes in .coffee files?

like image 23
Jamesgt Avatar answered Oct 31 '22 00:10

Jamesgt


The grunt.event.on event detects changes in files, receiving an action and filepath parameter.

Here's an untested example based on one of my gruntfiles. In this case, all my source coffeescript files are kept in a directory called sources, and for previewing they are compiled and saved to an identical directory structure under a directory called dev

SOURCES_DIR = 'sources'
DEV_DIR = 'dev'

grunt.initConfig
  watch :
    all :
      files : ["**/*.coffee"]
  coffee :
    dev :
      files :
        dest : "app.js"
grunt.loadNpmTasks 'grunt-contrib-watch'
grunt.loadNpmTasks 'grunt-contrib-coffee'

grunt.registerTask 'build', ['coffee:dev']

grunt.event.on('watch', (action,filepath) ->
  # Determine the full directory of the changed file
  wdi = filepath.lastIndexOf '/'
  wd =  filepath.substring 0,wdi

  # remove `sources` prefix from that directory
  fpath = wd.replace(SOURCES_DIR,'') + '/'

  # determine the filename
  fnamei = filepath.lastIndexOf '.'
  fname = filepath.substring wdi+1,fnamei # NOTE: this breaks the case where in same dir

  # concatenate fpath and fname with the dir to be compiled into
  deststr = "#{DEV_DIR}#{fpath}#{fname}.coffee"


  # set coffee.dev.files value in the coffee task to have am entry of form {"destination":"source"}
  obj = {}
  obj[deststr] = filepath
  grunt.config "coffee.dev.files", obj

  # fire the coffee task
  grunt.task.run "coffee"
)

Hope that helps.

EDIT: Probably not exactly what you want - because no doubt you want access to intermediary variables, actions and so forth - but you could use grunt to just run a shell coffee command. The grunt-shell npm task does this, for example

EDIT2: I've faced continued problems with grunt.watch.on not working consistently in grunt 0.4.1 on OSX 10.8 and MacVim 7.3; for whatever reason, it stops watching. I've reverted back to just using the basic grunt initConfig object but with much more granularity so it only watches and compiles relatively small groups of files rather than the whole lot. This slows down the build time considerably, but it much more robust. Your mileage may very.

like image 1
Jof Arnold Avatar answered Oct 31 '22 01:10

Jof Arnold