csssassgruntjsyeomangrunt-contrib-sass

Grunt dynamic dest location sass


This could possibly be a repeat question but I couldn't figure out a solution for my requirement

I am trying to create a sass grunt task which can generate css files in a dynamic location. Here is my structure

/components
 --> xyz 
   --> scss
     --> xyz.a.scss
     --> xyz.b.scss
 --> abc
   --> scss
     --> abc.a.scss
     --> abc.b.scss

Can the grunt task create a new folder relative to its component i.e

/components
 --> xyz
   --> scss
     --> xyz.a.scss
     --> xyz.b.scss
   --> css
     --> xyz.a.css
     --> xyz.b.css
 --> abc
   --> scss
     --> abc.a.scss
     --> abc.b.scss
   --> css
     --> abc.a.css
     --> abc.b.css

My current SASS task, generates CSS files in the same folder of SCSS

sass: {
     dist: {
          files: [{
            expand: true,
            cwd: '<%= yeoman.client %>/components/',
            src: ['**/*.scss'],
            dest: '<%= yeoman.client %>/components/',
            extDot: 'last',
            ext: '.css'
          }]
     }
},

I understand we could achieve this by providing component folder name in the dest, for example for xyz component I could use dest as <%= yeoman.client %>/components/xyz/css. But I will have to write seperate task for each component. Is there a way to keep dest in the same parent folder without actually specifying the name of the folder? i.e src: ['**/scss/*.scss'] and dest be: ['**/css/'] Is there a way to do this?


Solution

  • You can use dynamic parameters to pass in the task:

    for example:

    grunt sass:xyz
    

    than in the code you can use something like this:

    sass: {
     dist: {
          files: [{
            expand: true,
            cwd: '<%= yeoman.client %>/components/',
            src: ['**/<%= grunt.task.current.args[0] %>/sass/*.scss'],
            dest: '<%= yeoman.client %>/components/<%= grunt.task.current.args[0] %>/css',
            extDot: 'last',
            ext: '.css'
          }]
     }
    },
    

    the only things that you must set is a generic task that execute it for all the components for example:

    grunt.registerTask('sassAll', [ 'sass:xyz', 'sass:abc' ]);
    

    you can even generate an array and cycling it:

    grunt.registerTask('sassAll', function() {
        gruntUtils.sassTasks.forEach(function(param){
            grunt.task.run('sass:' + param);
        });
    });
    
    var gruntUtils = {
        sassTasks : [ 'xyz', 'abc' ]
    };
    

    you can use even more parameters for setting dest and source:

    grunt sass:xyz/sass:xyz/css
    

    and reference to the second parameter:

    <%= grunt.task.current.args[1] %>
    

    I found a way to retrive the directory(not sub-directory) inside a base one:

    var templates = grunt.file.expand({
                    filter: "isDirectory", 
                    cwd: "(your base dir path in relation to the gruntfile.js)/components"
                    },["*"]);
    
    var dirs = templates.map(function (t) {
        return t;
    });
    

    than you have an array(dirs) to use instead of [ 'xyz', 'abc' ]