-->

Interpolated array in Grunt template is interprete

2019-09-15 18:16发布

问题:

Previous title: "Why is Grunt's concat task not using dynamic configuration values?"

I am trying to dynamically configure the files that are concatenated by Grunt, and in doing so I came across this issue where the grunt-contrib-concat plugin does not seem to pick up the dynamically set values. At first I thought I was doing something wrong, but after creating my own task and using the same dynamic values everything came out just as intended. So that leaves the question of why is the grunt concat task not doing picking up and using the same values?

A gruntfile that reproduces the behaviour is seen below (gist: fatso83/73875acd1fa3662ef360).

// Grunt file that shows how dynamic config (and option!) values
// are not used in the grunt-contrib-concat task. Run using 'grunt'
module.exports = function(grunt){

    grunt.initConfig({

        concat : {
            foo : {
                nonull : true,
                src: '<%= grunt.config.get("myfiles") %>',
                dest : 'outfile.txt'
            }
        },

        myTask : {
            bar : '<%= grunt.config.get("myfiles") %>'
        }
    });

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

    grunt.registerMultiTask('myTask', function() {
        grunt.log.writeln('myTask:' + this.target + ' data=' + this.data);
    });

    grunt.registerTask('default', ['myTask','concat']);

    grunt.config.set('myfiles',['file1.txt', 'file2.txt'])
}

EDIT: A new lead: After literally hours of going nowhere I came across this sentence on Grunt's homepage:

nonull If set to true then the operation will include non-matching patterns. Combined with grunt's --verbose flag, this option can help debug file path issues.

Adding that to the config (edited above to reflect this) I got this error message which at least show that something is doing something with the dynamic values:

Running "concat:foo" (concat) task
>> Source file "file1.txt,file2.txt" not found.
Warning: Unable to write "outfile.txt/file1.txt,file2.txt" file 
(Error code: ENOTDIR). Use --force to continue.

After some more debugging in the other task, myTask, I have found out that the data sent in to the task as this.data is a string value, not an array. This is perhaps not very surprising, given that we do string interpolation, but this is not consistent with other interpolation features. For instance will <%= otherTask.fooTarget.src %> get the other task's src property as an array value.

Now the question is really how can I avoid passing the interpolated value as an array, rather than a string, to the concat task?

回答1:

Updated after reading up on the Grunt source code

After I found out that the problem was our array was interpreted as a string I quickly found a related question with a solution that seemed promising. Simply by enclosing the interpolated array string with curly brackets Grunt was able to find the files!

Unfortunately, the globbing pattern we are effectively creating does not preserve the specified file order. In the related question above I posted a thorough explanation of what was going on and how you can work around it in the general case.

For my specific case, where I reference a field in the configuration object there is actually no need for a function call to retreive it as it is directly available in the templates own scope! Therefore, instead of calling grunt.config.get('myfiles'), I can simply do <%= myfiles %>.

For the example above:

grunt.initConfig({

    concat : {
        foo : {
            nonull : true,
            src: '<%= myfiles %>',
            dest : 'outfile.txt'
        }
    },

    myTask : {
        bar : '<%= myfiles %>'
    }
});