tschaub / grunt-newer

Configure Grunt tasks to run with newer files only.
https://npmjs.org/package/grunt-newer
MIT License
945 stars 53 forks source link

Using newer to compile LESS file with imports #29

Open Poplava opened 10 years ago

Poplava commented 10 years ago

Newer task doesn't watch to LESS file imports.

When file a.less imports file b.less and we have modify b.less, newer task doesn't recompile a.less.

tschaub commented 10 years ago

See also #18. I've got a general purpose fix in mind. Just need some time to implement it.

mdedetrich commented 10 years ago

Im also experiencing this issue, however wouldn't be able to manually specify a src directory for a newer watching a task, and just to run the main task, would solve this issue easily?

In other words, generally speaking most people store all of their less/css in a single (or multiple) folders, and generally an @import statement in less will always point to a file inside those directories/s

So you can safely say, when one of those files changed, you will need to run the grunt:less command to produce your final css file. Doing https://github.com/tschaub/grunt-newer/pull/18 seems like overkill, as essentially newer would need to reimplement dependency resolution of something not related to newer at all (in this case it would have to implement dependency resolution of how less handles @import just to figure out what is a less src).

The issue in my case is that if I try to specify a src option in my less task, although newer will correctly watch the directory, it obviously messes with the original less (since it causes it to compile every single file in src, instead of just the ones specified in files)

tldr, Wouldn't a simple option for newer is to just allow you specify a src directory, *without altering any other tasks (something like scanDir)? This would solve the issue easily without having to do really complex stuff that is outside of newers domain.

Poplava commented 10 years ago

I don't think that grunt-newer task should look at @import files at all... It'll be hard to implement many dependencies lile less, sass, stylus, etc. I think it'll be right decision to fork grunt-newer task and create grunt-newer-less (or grunt-newer-sass, etc) task from it. I could help to implement this in my spare time.

tschaub commented 10 years ago

Take a look at #35 for my proposed solution. This is not specific to LESS, but it should be possible to make things work. The idea is to provide an override function that can do some additional checks to see if a file should be included for processing. So to support LESS imports, the function would look something like this:

  newer: {
    options: {
      override: function(taskName, targetName, filePath, time, include) {
        if (taskName === 'less') {
          // call include with `true` if there are newer imports          
          checkForNewerImports(filePath, time, include);
        } else {
          include(false);
        }
      }
    }
  }

It should be possible to put together a separate module that provides something like the checkForNewerImports function.

Poplava commented 10 years ago

I think it's good decision! Now I'm working on huge project deployment system based on GruntJS. And I'll use newer for many tasks. And I'll try this override function for LESS compiling. Thanks!

cgmartin commented 10 years ago

Here's an example checkForNewerImports fn that works for my setup, in case it helps anyone: https://gist.github.com/cgmartin/10328349

bellerus commented 10 years ago

If anyone needs, I made a coffeescript version of @cgmartin's solution: https://gist.github.com/bellerus/10414499

madsleejensen commented 10 years ago

I created a new version that supports "Less import options" like 'import (reference) "file.less"' http://lesscss.org/features/#import-options, also i made it completely async and added recursive lookup, so it will look deeper than the first level of import's.

(im using https://github.com/caolan/async#memoize to prevent lookup on the same files multiple times)

https://gist.github.com/madsleejensen/11082646

tschaub commented 10 years ago

Looks very nice @madsleejensen. I'd like to make it easier for people to use this. I'll try to experiment with a few options before too long (traveling for the next week, so it won't be immediately).

mdedetrich commented 10 years ago

Would like to mention, although this isn't directly related to less, the same issue happens when using jade mixins (i.e. you have a jade file bar using a mixin foo which is in a separate file, when foo is changed, bar is never recompiled)

chrisSowerby commented 9 years ago

Please can you help me. I get this error when attempting to set this up: Fatal error: undefined is not a function

This is my full gruntfile thank you:

https://github.com/chrisSowerby/grunt/blob/master/Gruntfile.js

hengkiardo commented 9 years ago

anyupdate about this issue? any plan to make it auto from plugins and instead extra options?

xiaogwu commented 9 years ago

I'd love to see a more all purpose solution that also works with sass imports.

tibineagu commented 8 years ago

@madsleejensen awesome gist, saved us a lot of trouble :) we had to adjust the regex a bit to support single-quotes on the imported file, but it does the job flawlessly.

@xiaogwu I think @madsleejensen 's fix works without any major changes for sass, just update line 55.

@tschaub while this kind of functionality is external to the scope of grunt-newer, it would be awesome if it could be integrated into the options a little more easily - still, you've created an amazing tool.

tfrommen commented 8 years ago

Just in case anyone still needs this, I came up with this simple delegation task that does the trick:

grunt.initConfig( {
    delegate: {
        some_other_TASK: {
            src: [ 'some/src/path/**/*.ext' ],
            dest: 'some/dest/path/'
        }
    }
} );

grunt.registerTask( 'delegate', function() {
    grunt.task.run( this.args.join( ':' ) );
} );

A complete example for grunt-contrib-sass would look like the following:

module.exports = function( grunt ) {
    require( 'load-grunt-tasks' )( grunt );

    grunt.initConfig( {
        delegate: {
            sass: {
                src: [ '<%= config.styles.src %>**/*.scss' ],
                dest: '<%= config.styles.dest %>'
            }
        },

        sass: {
            styles: {
                expand: true,
                cwd: '<%= config.styles.src %>',
                src: [ '*.scss' ],
                dest: '<%= config.styles.dest %>',
                ext: '.css'
            }
        }
    } );

    grunt.registerTask( 'delegate', function() {
        grunt.task.run( this.args.join( ':' ) );
    } );
};

You just have to call newer:delegate:sass:styles (via CLI, or some other task). grunt-newer checks the files given in the according delegate target (where I have the globbing pattern **/ included). If there are new files found (also .scss files in subfolders), the according sass task (with the given target) will be called. A solution for LESS should look pretty much the same, I guess.

I'm unsure, though, if making a separate grunt plugin would be of use here.

Maybe you can add something like my delegate task to grunt-newer, @tschaub?

@aredo @bellerus @cgmartin @chrisSowerby @madsleejensen @Poplava @tibineagu @tschaub @xiaogwu