0

How can I set up my grunt script to run a less task on multiple files that the watch task detects? Is it possible to do this without using a "grunt.event.on('watch'..." hack?

This solution works with one file, but when two files are saved at the same time (in Visual Studio) only one css is generated.

The script:

'useStrict';
module.exports = function (grunt) {
    grunt.initConfig({
        globalConfig: globalConfig,
        less: {
            all: {
                options: {
                    compress: false,
                },
                files: '',
            },
        },
        watch: {
            all: {
                files: [
                        'Main/**/*.less',                       
                ],
                tasks: ['less'],
                options: {
                    nospawn: true
                }
            }
        }       
    });

    grunt.loadNpmTasks('grunt-contrib-less');
    grunt.loadNpmTasks('grunt-contrib-watch');

    grunt.event.on('watch', function(action, filepath) {

        // Handling .less imports so that when the watch task
        // detects change in an imported file, "the main .less file
        // that does the import" is compiled, instead of the imported file.
        // Naming convention for imported files: Title of main file that 
        // imports + "-" + name describing the imported file
        // E.g. Main.less, Main-Colors.less, Main-Structure.less, Main-Utility.less

        var splittedPath = filepath.split('/');
        var filename = splittedPath[splittedPath.length - 1];
        delete splittedPath[splittedPath.length - 1];
        var fileDirectoryPath = splittedPath.join('/');
        var splittedFilename = filename.split('-');
        if (splittedFilename.length > 1){
            filepath = fileDirectoryPath + splittedFilename[0] + '.less';
        }

        grunt.config(['less', 'all', 'files'], [{
            expand: true,
            src: filepath,
            ext: '.css',
        }]);
    });

    grunt.registerTask('default', ['watch']);
};

All help appreciated! Thanks!

henrikh
  • 113
  • 9

1 Answers1

1

After some research and help on the grunt-contrib-watch forum I managed to find the answer to my question.

First of all it's not possible to this without the "grunt.event.on('watch'..." hack.

The way to implement that several files is saved at the same time is found here and is easy to implement: https://github.com/gruntjs/grunt-contrib-watch#compiling-files-as-needed

The result of my updated code solving this issue:

'useStrict';
module.exports = function (grunt) {
    grunt.initConfig({
        globalConfig: globalConfig,
        less: {
            all: {
                files: 'event will load filepaths on the fly',
                options: {
                    compress: false,
                }
            },
        },
        watch: {
            all: {
                files: ['Main/**/*.less'],
                tasks: ['less'],
                options: {
                    nospawn: true
                }
            }
        }       
    });

    grunt.loadNpmTasks('grunt-contrib-less');
    grunt.loadNpmTasks('grunt-contrib-watch');

    var changedFiles = Object.create(null);
    var onChange = grunt.util._.debounce(function() {
        grunt.config(['less', 'all', 'files'], [{
            expand: true,
            src: Object.keys(changedFiles),
            ext: '.css',
        }]);
        changedFiles = Object.create(null);
    }, 200);

    grunt.event.on('watch', function(action, filepath) {
        // Handling .less imports so that when the watch task
        // detects change in an imported file the main .less file
        // that imports is compiled instead of the imported file.
        // Naming convention for imported files:
        // title of main file that imports + "-" + name describing the imported file
        var splittedPath = filepath.split('/');
        var filename = splittedPath[splittedPath.length - 1];
        delete splittedPath[splittedPath.length - 1];
        var fileDirectoryPath = splittedPath.join('/');
        var splittedFilename = filename.split('-');
        if (splittedFilename.length > 1){
            filepath = fileDirectoryPath + splittedFilename[0] + '.less';
        }

        changedFiles[filepath] = action;
        onChange();
    });

    grunt.registerTask('default', ['watch']);
};
henrikh
  • 113
  • 9