简体   繁体   中英

grunt watch - use files array format as source

I'm using grunt-contrib-less and grunt-contrib-watch together. My less task uses the files array format to define multiple src and dest's. I'd like to reference those same files from the watch task. Like this:

grunt.initConfig({
  less: {
    build: {
      files: [
        {src: 'src/aa.less', dest: 'dest/a.css'},
        {src: 'src/aa1.less', dest: 'dest/a1.css'}
      ]
    }
  },
  watch: {
    less: {
      files: '<%= less.build.files %>',
      tasks: ['less']
    }
  }
});

That underscore template works, but watch can't process the files array format, it only accepts file input as a string or array of strings. Here's what I've tried:

  • '<%= less.build.files.src %>' doesn't work because less.build.files is an array, not an object.

  • '<%= _(less.build.files).pluck("src").value() %>' doesn't work, because even though it makes the right file list, it resolves to single string 'src/aa.less,src/aa1.less' , not an array.

  • '{<%= _(less.build.files).pluck("src") %>}' does work, as suggested here https://stackoverflow.com/a/21608021/490592 , but it doesn't feel right. I'm trying to target a specific set of files, not pattern match from my whole project directory.

  • grunt.config.set('watch.less.files', _(grunt.config.get('less.build.files')).pluck('src').value()); works, but this must be separate from the initConfig.

Is there a more elegant way to accomplish this?

I confirmed that grunt-contrib-watch does not support the files array format. I settled on using the grunt-config-set technique I mentioned above.

Even though watch doesn't support the files array format, I make sure my custom tasks are compatible with it so I don't have to use the workarounds from my question. I've attached an example. For read-only tasks, I add a useDest option, so they can be configured to operate on dest's instead of src's. This helps when you want to "pipe" one task into another task.

module.exports = function (grunt) {

  grunt.registerMultiTask('example', 'Example read-only task', function () {
    var options = this.options({
          useDest: false, // When true, operate on dest files, instead of src
        });
        files = this.files.map(function (file) {
          return { src: (options.useDest) ? [file.dest] : file.src }
        });
    files.forEach(function (file) {
      grunt.log.writeln('Source: ' + grunt.log.wordlist(file.src));
    });
  });

  grunt.loadNpmTasks('grunt-contrib-concat');

  grunt.initConfig({
    concat: {
      build: {
        files: [
          { src: 'node_modules/grunt/lib/grunt/*.js', dest: 'lib.js' },
          { src: 'node_modules/grunt/internal-tasks/*.js', dest: 'tasks.js' }
        ]
      }
    },
    example: {
      build: {
        options: {
          useDest: true
        },
        files: '<%= concat.build.files %>'
      }
    }
  });

};

The task will output:

Running "example:build" (example) task
Source: lib.js
Source: tasks.js

I don't understand why you haven't simply refactored the files section into a variable? The following achieves your goal of "like to reference those same files from the watch task."

var yourFiles = [
    {src: 'src/aa.less', dest: 'dest/a.css'},
    {src: 'src/aa1.less', dest: 'dest/a1.css'}
];

grunt.initConfig({
    less: {
        build: {
            files: yourFiles 
        }
    },
    watch: {
        less: {
            files: yourFiles 
            tasks: ['less']
        }
    }
});

PS You might enjoy reading up on this to know what happens under the hood when referencing variables in the templates, for some more advanced hacking later on.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM