sassgruntjscompass-sassgrunt-contrib-compass

Compass plugin with Grunt


This is a question about how to use Compass with Grunt. Something goes wrong in the data filling step. I noticed on the console that, when I modify only a .scss file, compass fills up the same file several times (four, five or up to ten). In your opinion, what does it depend on? Here is my gruntfile.js. Thank you for your kind help.

module.exports = function (grunt) {

var _homeJs = ['contents/js/jquery.Cinema.js', 'contents/js/jquery.SkinOverlay.js'];
var _homeJsExclude = []

_homeJs.forEach(function (entry) {
    _homeJsExclude.push('!' + entry)
});


grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),

    concat: {
        dist: {
            src: ['contents/js/*.js', _homeJsExclude],
            dest: 'contents/dist/js/global.js'
        },
        lib: {
            src: 'contents/plugins/**/*.js',
            dest: 'contents/dist/js/libs.js'
        },
        globalhome: {
            files: {
                'contents/dist/js/global.home.js': _homeJs
            }
        }
    },
    uglify: {
        dist: {
            src: ['<%= concat.dist.dest %>'],
            dest: 'contents/dist/js/global.min.js'
        },
        globalhome_min: {
            src: 'contents/dist/js/global.home.js',
            dest: 'contents/dist/js/global.home.min.js'
        },
        lib: {
            src: ['<%= concat.lib.dest %>'],
            dest: 'contents/dist/js/libs.min.js'
        }
    },
    compass: {
        dist: {
            options: {
                sassDir: 'contents/sass/',
                cssDir: 'contents/dist/css',
                watch: true,
                outputStyle: 'compressed',
                linecomments: false
            }
        }
    },
    cssmin: {
        target: {
            files: [
                {
                    './contents/dist/css/ie-css/ie8/ie8.min.css': ['./contents/css/ie-css/ie8/ie8.css']
                },
                {
                    './contents/dist/css/main.min.css': ['./contents/dist/css/main.css']
                },
                {
                    './contents/dist/css/responsive.min.css': ['./contents/dist/css/responsive.css']
                }
            ]
        }
    },
    concurrent: {
        target: {
            tasks: ['compass', 'watch'],
            options: {
                logConcurrentOutput: true
            }
        }
    },
    watch: {
        js: {
            files: ['contents/js/*.js', 'contents/plugins/**/*.js'],
            tasks: ['concat', 'uglify:dist', 'uglify:globalhome_min'],
            options: {
                reload: true
            }
        },
        css: {
            files: ['contents/sass/**/*.scss', 'contents/dist/css/'],
            tasks: ['concurrent:target'], 
            options: {
                reload: true
            }
        }
    },
});

grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-compass');
grunt.loadNpmTasks('grunt-concurrent');
grunt.loadNpmTasks('grunt-contrib-cssmin');

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

};


Solution

  • You've got a couple problems here... First, you're watching your sass files in the compass task already, there is no need to monitor them with an explicit watch task. Additionally, your concurrent task is set to run watch again once the sass files change.

    This is the logic flow you have set up right now:

    1. Start watch, it waits for sass OR compiled css files to change
    2. When a sass file changes, watch executes concurrent, which in turn executes compass, then another instance of watch.
    3. The compass task compiles your css, which causes the watch task to detect the changes and run the concurrent task again.
    4. This continues and ruins everything.

    So, instead of what you have now, just use this (simplified) config:

    grunt.initConfig({
        // ...
    
        compass: {
            dist: {
                options: {
                    sassDir: 'contents/sass/',
                    cssDir: 'contents/dist/css',
    
                    // *** remove this option
                    // watch: true,
    
                    outputStyle: 'compressed',
                    linecomments: false
                }
            }
        },
        // ...
    
        // *** remove this whole task, in the current config you do not need it
        /*
        concurrent: {
            target: {
                tasks: ['compass', 'watch'],
                options: {
                    logConcurrentOutput: true
                }
            }
        },
        */
        watch: {
            // ...
    
            css: {
                // *** only watch the source files, not the output
                files: ['contents/sass/**/*.scss'],
                // *** run the `compass` task directly
                tasks: ['compass'], 
                options: {
                    reload: true
                }
            }
        }
    });
    

    The you kick the whole thing off with:

    ~/my-project$ grunt watch
    

    Or if you want to run compass first, then watch for changes:

    ~/my-project$ grunt compass watch