title: Setting up compass using the Yeoman angular-fullstack Gruntfile.js
body: <p>I have a super complex grunt file that has been generated from <a href="https://www.npmjs.org/package/generator-angular-fullstack" rel="nofollow">Angular FullStack</a></p>
  
  <p>I want to add a gem called <a href="https://rubygems.org/gems/susy" rel="nofollow">Susy</a> but it has a dependency of <a href="https://rubygems.org/gems/compass" rel="nofollow">compass</a>:</p>
  
  <p>In the past i've been able to do this simply by adding: <code>require</code> to my grunt file</p>
  
  <pre><code>compass: {
    options: {
    require: ['susy', 'breakpoint']
  }
  </code></pre>
  
  <p>Unfortunately I don't have a similar compass code block in this Grunt file.</p>
  
  <p><strong>QUESTION:</strong></p>
  
  <p><strong>How can I add compass to my Gruntfile.js to watch my sass so that that I may use compass gems like Susy?</strong></p>
  
  <p>Heres a link to <a href="https://github.com/matthewharwood/harwood/blob/master/Gruntfile.js" rel="nofollow">git</a> (cuz I know it's long ) :c</p>
  
  <pre><code>// Generated on 2014-09-01 using generator-angular-fullstack 2.0.13
  'use strict';
  
  module.exports = function (grunt) {
    var localConfig;
    try {
      localConfig = require('./server/config/local.env');
    } catch(e) {
      localConfig = {};
    }
  
    // Load grunt tasks automatically, when needed
    require('jit-grunt')(grunt, {
      express: 'grunt-express-server',
      useminPrepare: 'grunt-usemin',
      ngtemplates: 'grunt-angular-templates',
      cdnify: 'grunt-google-cdn',
      protractor: 'grunt-protractor-runner',
      injector: 'grunt-asset-injector',
      buildcontrol: 'grunt-build-control',
      pagespeed: 'grunt-pagespeed',
      responsive: 'grunt-responsive-images',
      autoshot: 'grunt-autoshot'
    });
  
    // Time how long tasks take. Can help when optimizing build times
    require('time-grunt')(grunt);
  
    // Define the configuration for all the tasks
    grunt.initConfig({
  
      // Project settings
      pkg: grunt.file.readJSON('package.json'),
      yeoman: {
        // configurable paths
        client: require('./bower.json').appPath || 'client',
        dist: 'dist'
      },
      express: {
        options: {
          port: process.env.PORT || 9000
        },
        dev: {
          options: {
            script: 'server/app.js',
            debug: true
          }
        },
        prod: {
          options: {
            script: 'dist/server/app.js'
          }
        }
      },
      open: {
        server: {
          url: 'http://localhost:&lt;%= express.options.port %&gt;'
        }
      },
      watch: {
        injectJS: {
          files: [
            '&lt;%= yeoman.client %&gt;/{app,components}/**/*.js',
            '!&lt;%= yeoman.client %&gt;/{app,components}/**/*.spec.js',
            '!&lt;%= yeoman.client %&gt;/{app,components}/**/*.mock.js',
            '!&lt;%= yeoman.client %&gt;/app/app.js'],
          tasks: ['injector:scripts']
        },
        injectCss: {
          files: [
            '&lt;%= yeoman.client %&gt;/{app,components}/**/*.css'
          ],
          tasks: ['injector:css']
        },
        mochaTest: {
          files: ['server/**/*.spec.js'],
          tasks: ['env:test', 'mochaTest']
        },
        jsTest: {
          files: [
            '&lt;%= yeoman.client %&gt;/{app,components}/**/*.spec.js',
            '&lt;%= yeoman.client %&gt;/{app,components}/**/*.mock.js'
          ],
          tasks: ['newer:jshint:all', 'karma']
        },
        injectSass: {
          files: [
            '&lt;%= yeoman.client %&gt;/{app,components}/**/*.{scss,sass}'],
          tasks: ['injector:sass']
        },
        sass: {
          files: [
            '&lt;%= yeoman.client %&gt;/{app,components}/**/*.{scss,sass}'],
          tasks: ['sass', 'autoprefixer']
        },
        jade: {
          files: [
            '&lt;%= yeoman.client %&gt;/{app,components}/*',
            '&lt;%= yeoman.client %&gt;/{app,components}/**/*.jade'],
          tasks: ['jade']
        },
        coffee: {
          files: [
            '&lt;%= yeoman.client %&gt;/{app,components}/**/*.{coffee,litcoffee,coffee.md}',
            '!&lt;%= yeoman.client %&gt;/{app,components}/**/*.spec.{coffee,litcoffee,coffee.md}'
          ],
          tasks: ['newer:coffee', 'injector:scripts']
        },
        coffeeTest: {
          files: [
            '&lt;%= yeoman.client %&gt;/{app,components}/**/*.spec.{coffee,litcoffee,coffee.md}'
          ],
          tasks: ['karma']
        },
        gruntfile: {
          files: ['Gruntfile.js']
        },
        livereload: {
          files: [
            '{.tmp,&lt;%= yeoman.client %&gt;}/{app,components}/**/*.css',
            '{.tmp,&lt;%= yeoman.client %&gt;}/{app,components}/**/*.html',
            '{.tmp,&lt;%= yeoman.client %&gt;}/{app,components}/**/*.js',
            '!{.tmp,&lt;%= yeoman.client %&gt;}{app,components}/**/*.spec.js',
            '!{.tmp,&lt;%= yeoman.client %&gt;}/{app,components}/**/*.mock.js',
            '&lt;%= yeoman.client %&gt;/assets/images/{,*//*}*.{png,jpg,jpeg,gif,webp,svg}'
          ],
          options: {
            livereload: true
          }
        },
        express: {
          files: [
            'server/**/*.{js,json}'
          ],
          tasks: ['express:dev', 'wait'],
          options: {
            livereload: true,
            nospawn: true //Without this option specified express won't be reloaded
          }
        }
      },
  
      // Make sure code styles are up to par and there are no obvious mistakes
      jshint: {
        options: {
          jshintrc: '&lt;%= yeoman.client %&gt;/.jshintrc',
          reporter: require('jshint-stylish')
        },
        server: {
          options: {
            jshintrc: 'server/.jshintrc'
          },
          src: [
            'server/**/*.js',
            '!server/**/*.spec.js'
          ]
        },
        serverTest: {
          options: {
            jshintrc: 'server/.jshintrc-spec'
          },
          src: ['server/**/*.spec.js']
        },
        all: [
          '&lt;%= yeoman.client %&gt;/{app,components}/**/*.js',
          '!&lt;%= yeoman.client %&gt;/{app,components}/**/*.spec.js',
          '!&lt;%= yeoman.client %&gt;/{app,components}/**/*.mock.js'
        ],
        test: {
          src: [
            '&lt;%= yeoman.client %&gt;/{app,components}/**/*.spec.js',
            '&lt;%= yeoman.client %&gt;/{app,components}/**/*.mock.js'
          ]
        }
      },
  
      // Empties folders to start fresh
      clean: {
        dist: {
          files: [{
            dot: true,
            src: [
              '.tmp',
              '&lt;%= yeoman.dist %&gt;/*',
              '!&lt;%= yeoman.dist %&gt;/.git*',
              '!&lt;%= yeoman.dist %&gt;/.openshift',
              '!&lt;%= yeoman.dist %&gt;/Procfile'
            ]
          }]
        },
        server: '.tmp'
      },
  
      // Add vendor prefixed styles
      autoprefixer: {
        options: {
          browsers: ['last 1 version']
        },
        dist: {
          files: [{
            expand: true,
            cwd: '.tmp/',
            src: '{,*/}*.css',
            dest: '.tmp/'
          }]
        }
      },
  
      // Debugging with node inspector
      'node-inspector': {
        custom: {
          options: {
            'web-host': 'localhost'
          }
        }
      },
  
      // Use nodemon to run server in debug mode with an initial breakpoint
      nodemon: {
        debug: {
          script: 'server/app.js',
          options: {
            nodeArgs: ['--debug-brk'],
            env: {
              PORT: process.env.PORT || 9000
            },
            callback: function (nodemon) {
              nodemon.on('log', function (event) {
                console.log(event.colour);
              });
  
              // opens browser on initial server start
              nodemon.on('config:update', function () {
                setTimeout(function () {
                  require('open')('http://localhost:8080/debug?port=5858');
                }, 500);
              });
            }
          }
        }
      },
  
      // Automatically inject Bower components into the app
      wiredep: {
        target: {
          src: '&lt;%= yeoman.client %&gt;/index.html',
          ignorePath: '&lt;%= yeoman.client %&gt;/',
          exclude: [/bootstrap-sass-official/, /bootstrap.js/, '/json3/', '/es5-shim/', /bootstrap.css/, /font-awesome.css/ ]
        }
      },
      // responsive: {
      //   dev: {
      //     options: {},
      //     sizes: [{
      //       width: 320,
      //       height: 240
      //     },{
      //       name: 'large',
      //       width: 640
      //     },{
      //       name: "large",
      //       width: 1024,
      //       suffix: "_x2",
      //       quality: 0.6
      //     }],
      //     files: [{
      //       expand: true,
      //       cwd: '&lt;%= yeoman.client %&gt;/assets/images',
      //       src: '{,*/}*.{png,jpg,jpeg,gif}',
      //       dest: 'dist/'
      //     }]
      //   }
      // },
  
      //autoshot the screen
      autoshot: {
          dist: {
              options: {
                  path: './screenshots/',
                  remote : {
                      files: [
                          { src: 'http://localhost:&lt;%= express.options.port %&gt;', dest: 'app.jpg'}
                      ]
                  },
                  viewport: ['320x480','480x320','384x640','640x384','602x963','963x602','600x960','960x600','800x1280','1280x800','768x1024','1024x768']
              }
          }
      },
  
      // Renames files for browser caching purposes 
  
      rev: {
        dist: {
          files: {
            src: [
              '&lt;%= yeoman.dist %&gt;/public/{,*/}*.js',
              '&lt;%= yeoman.dist %&gt;/public/{,*/}*.css',
              '&lt;%= yeoman.dist %&gt;/public/assets/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
              '&lt;%= yeoman.dist %&gt;/public/assets/fonts/*'
            ]
          }
        }
      },
  
      // Reads HTML for usemin blocks to enable smart builds that automatically
      // concat, minify and revision files. Creates configurations in memory so
      // additional tasks can operate on them
      useminPrepare: {
        html: ['&lt;%= yeoman.client %&gt;/index.html'],
        options: {
          dest: '&lt;%= yeoman.dist %&gt;/public'
        }
      },
  
      // Performs rewrites based on rev and the useminPrepare configuration
      usemin: {
        html: ['&lt;%= yeoman.dist %&gt;/public/{,*/}*.html'],
        css: ['&lt;%= yeoman.dist %&gt;/public/{,*/}*.css'],
        js: ['&lt;%= yeoman.dist %&gt;/public/{,*/}*.js'],
        options: {
          assetsDirs: [
            '&lt;%= yeoman.dist %&gt;/public',
            '&lt;%= yeoman.dist %&gt;/public/assets/images'
          ],
          // This is so we update image references in our ng-templates
          patterns: {
            js: [
              [/(assets\/images\/.*?\.(?:gif|jpeg|jpg|png|webp|svg))/gm, 'Update the JS to reference our revved images']
            ]
          }
        }
      },
  
      // The following *-min tasks produce minified files in the dist folder
      imagemin: {
        dist: {
          files: [{
            expand: true,
            cwd: '&lt;%= yeoman.client %&gt;/assets/images',
            src: '{,*/}*.{png,jpg,jpeg,gif}',
            dest: '&lt;%= yeoman.dist %&gt;/public/assets/images'
          }]
        }
      },
  
      svgmin: {
        dist: {
          files: [{
            expand: true,
            cwd: '&lt;%= yeoman.client %&gt;/assets/images',
            src: '{,*/}*.svg',
            dest: '&lt;%= yeoman.dist %&gt;/public/assets/images'
          }]
        }
      },
  
      // Allow the use of non-minsafe AngularJS files. Automatically makes it
      // minsafe compatible so Uglify does not destroy the ng references
      ngAnnotate: {
        dist: {
          files: [{
            expand: true,
            cwd: '.tmp/concat',
            src: '*/**.js',
            dest: '.tmp/concat'
          }]
        }
      },
  
      //allows pages speed results
      //
      pagespeed: {
        options: {
          nokey: true,
          url: "0.0.0.0:9000"
        },
        prod: {
          options: {
            url: "https://developers.google.com/speed/docs/insights/v1/getting_started",
            locale: "en_GB",
            strategy: "desktop",
            threshold: 80
          }
        },
        paths: {
          options: {
            paths: ["/speed/docs/insights/v1/getting_started", "/speed/docs/about"],
            locale: "en_GB",
            strategy: "desktop",
            threshold: 80
          }
        }
      },
      // Package all the html partials into a single javascript payload
      ngtemplates: {
        options: {
          // This should be the name of your apps angular module
          module: 'morningharwoodApp',
          htmlmin: {
            collapseBooleanAttributes: true,
            collapseWhitespace: true,
            removeAttributeQuotes: true,
            removeEmptyAttributes: true,
            removeRedundantAttributes: true,
            removeScriptTypeAttributes: true,
            removeStyleLinkTypeAttributes: true
          },
          usemin: 'app/app.js'
        },
        main: {
          cwd: '&lt;%= yeoman.client %&gt;',
          src: ['{app,components}/**/*.html'],
          dest: '.tmp/templates.js'
        },
        tmp: {
          cwd: '.tmp',
          src: ['{app,components}/**/*.html'],
          dest: '.tmp/tmp-templates.js'
        }
      },
  
      // Replace Google CDN references
      cdnify: {
        dist: {
          html: ['&lt;%= yeoman.dist %&gt;/public/*.html']
        }
      },
  
      // Copies remaining files to places other tasks can use
      copy: {
        dist: {
          files: [{
            expand: true,
            dot: true,
            cwd: '&lt;%= yeoman.client %&gt;',
            dest: '&lt;%= yeoman.dist %&gt;/public',
            src: [
              '*.{ico,png,txt}',
              '.htaccess',
              'bower_components/**/*',
              'assets/images/{,*/}*.{webp}',
              'assets/fonts/**/*',
              'index.html'
            ]
          }, {
            expand: true,
            cwd: '.tmp/images',
            dest: '&lt;%= yeoman.dist %&gt;/public/assets/images',
            src: ['generated/*']
          }, {
            expand: true,
            dest: '&lt;%= yeoman.dist %&gt;',
            src: [
              'package.json',
              'server/**/*'
            ]
          }]
        },
        styles: {
          expand: true,
          cwd: '&lt;%= yeoman.client %&gt;',
          dest: '.tmp/',
          src: ['{app,components}/**/*.css']
        }
      },
  
      buildcontrol: {
        options: {
          dir: 'dist',
          commit: true,
          push: true,
          connectCommits: false,
          message: 'Built %sourceName% from commit %sourceCommit% on branch %sourceBranch%'
        },
        heroku: {
          options: {
            remote: 'heroku',
            branch: 'master'
          }
        },
        openshift: {
          options: {
            remote: 'openshift',
            branch: 'master'
          }
        }
      },
  
      // Run some tasks in parallel to speed up the build process
      concurrent: {
        server: [
          'coffee',
          'jade',
          'sass',
        ],
        test: [
          'coffee',
          'jade',
          'sass',
        ],
        debug: {
          tasks: [
            'nodemon',
            'node-inspector'
          ],
          options: {
            logConcurrentOutput: true
          }
        },
        dist: [
          'coffee',
          'jade',
          'sass',
          'imagemin',
          'svgmin'
        ]
      },
  
      // Test settings
      karma: {
        unit: {
          configFile: 'karma.conf.js',
          singleRun: true
        }
      },
  
      mochaTest: {
        options: {
          reporter: 'spec'
        },
        src: ['server/**/*.spec.js']
      },
  
      protractor: {
        options: {
          configFile: 'protractor.conf.js'
        },
        chrome: {
          options: {
            args: {
              browser: 'chrome'
            }
          }
        }
      },
  
      env: {
        test: {
          NODE_ENV: 'test'
        },
        prod: {
          NODE_ENV: 'production'
        },
        all: localConfig
      },
  
      // Compiles Jade to html
      jade: {
        compile: {
          options: {
            data: {
              debug: false
            }
          },
          files: [{
            expand: true,
            cwd: '&lt;%= yeoman.client %&gt;',
            src: [
              '{app,components}/**/*.jade'
            ],
            dest: '.tmp',
            ext: '.html'
          }]
        }
      },
  
      // Compiles CoffeeScript to JavaScript
      coffee: {
        options: {
          sourceMap: true,
          sourceRoot: ''
        },
        server: {
          files: [{
            expand: true,
            cwd: 'client',
            src: [
              '{app,components}/**/*.coffee',
              '!{app,components}/**/*.spec.coffee'
            ],
            dest: '.tmp',
            ext: '.js'
          }]
        }
      },
  
      // Compiles Sass to CSS
      sass: {
        server: {
          options: {
            loadPath: [
              '&lt;%= yeoman.client %&gt;/bower_components',
              '&lt;%= yeoman.client %&gt;/app',
              '&lt;%= yeoman.client %&gt;/components'
            ],
            compass: false
          },
          files: {
            '.tmp/app/app.css' : '&lt;%= yeoman.client %&gt;/app/app.scss'
          }
        }
      },
  
      injector: {
        options: {
  
        },
        // Inject application script files into index.html (doesn't include bower)
        scripts: {
          options: {
            transform: function(filePath) {
              filePath = filePath.replace('/client/', '');
              filePath = filePath.replace('/.tmp/', '');
              return '&lt;script src="' + filePath + '"&gt;&lt;/script&gt;';
            },
            starttag: '&lt;!-- injector:js --&gt;',
            endtag: '&lt;!-- endinjector --&gt;'
          },
          files: {
            '&lt;%= yeoman.client %&gt;/index.html': [
                ['{.tmp,&lt;%= yeoman.client %&gt;}/{app,components}/**/*.js',
                 '!{.tmp,&lt;%= yeoman.client %&gt;}/app/app.js',
                 '!{.tmp,&lt;%= yeoman.client %&gt;}/{app,components}/**/*.spec.js',
                 '!{.tmp,&lt;%= yeoman.client %&gt;}/{app,components}/**/*.mock.js']
              ]
          }
        },
  
        // Inject component scss into app.scss
        sass: {
          options: {
            transform: function(filePath) {
              filePath = filePath.replace('/client/app/', '');
              filePath = filePath.replace('/client/components/', '');
              return '@import \'' + filePath + '\';';
            },
            starttag: '// injector',
            endtag: '// endinjector'
          },
          files: {
            '&lt;%= yeoman.client %&gt;/app/app.scss': [
              '&lt;%= yeoman.client %&gt;/{app,components}/**/*.{scss,sass}',
              '!&lt;%= yeoman.client %&gt;/app/app.{scss,sass}'
            ]
          }
        },
  
        // Inject component css into index.html
        css: {
          options: {
            transform: function(filePath) {
              filePath = filePath.replace('/client/', '');
              filePath = filePath.replace('/.tmp/', '');
              return '&lt;link rel="stylesheet" href="' + filePath + '"&gt;';
            },
            starttag: '&lt;!-- injector:css --&gt;',
            endtag: '&lt;!-- endinjector --&gt;'
          },
          files: {
            '&lt;%= yeoman.client %&gt;/index.html': [
              '&lt;%= yeoman.client %&gt;/{app,components}/**/*.css'
            ]
          }
        }
      },
    });
  
    // Used for delaying livereload until after server has restarted
    grunt.registerTask('wait', function () {
      grunt.log.ok('Waiting for server reload...');
  
      var done = this.async();
  
      setTimeout(function () {
        grunt.log.writeln('Done waiting!');
        done();
      }, 1500);
    });
  
    grunt.registerTask('express-keepalive', 'Keep grunt running', function() {
      this.async();
    });
  
    grunt.registerTask('serve', function (target) {
      if (target === 'dist') {
        return grunt.task.run(['build', 'env:all', 'env:prod', 'express:prod', 'wait', 'open', 'express-keepalive']);
      }
  
      if (target === 'debug') {
        return grunt.task.run([
          'clean:server',
          'env:all',
          'injector:sass', 
          'concurrent:server',
          'injector',
          'wiredep',
          'autoprefixer',
          'concurrent:debug'
        ]);
      }
  
      grunt.task.run([
        'clean:server',
        'env:all',
        'injector:sass', 
        'concurrent:server',
        'injector',
        'wiredep',
        'autoprefixer',
        'express:dev',
        'wait',
        'open',
        'watch'
      ]);
    });
  
    grunt.registerTask('server', function () {
      grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
      grunt.task.run(['serve']);
    });
  
    grunt.registerTask('test', function(target) {
      if (target === 'server') {
        return grunt.task.run([
          'env:all',
          'env:test',
          'mochaTest'
        ]);
      }
  
      else if (target === 'client') {
        return grunt.task.run([
          'clean:server',
          'env:all',
          'injector:sass', 
          'concurrent:test',
          'injector',
          'autoprefixer',
          'karma',
          'autoshot'
        ]);
      }
  
      else if (target === 'e2e') {
        return grunt.task.run([
          'clean:server',
          'env:all',
          'env:test',
          'injector:sass', 
          'concurrent:test',
          'injector',
          'wiredep',
          'autoprefixer',
          'express:dev',
          'protractor'
        ]);
      }
  
      else grunt.task.run([
        'test:server',
        'test:client'
      ]);
    });
  
    grunt.registerTask('build', [
      'clean:dist',
      'injector:sass', 
      'concurrent:dist',
      'injector',
      'wiredep',
      // 'responsive'
      'useminPrepare',
      'autoprefixer',
      'ngtemplates',
      'concat',
      'ngAnnotate',
      'copy:dist',
      'cdnify',
      'cssmin',
      'uglify',
      'rev',
      'usemin',
      'pagespeed'
    ]);
    grunt.registerTask('default', [
      'newer:jshint',
      'test',
      'build'
    ]);
  
  };
  </code></pre>
  
  <p>UPDATE:</p>
  
  <pre><code>  // Compiles Sass to CSS and generates necessary files if requested
      compass: {
        options: {
          sassDir: '&lt;%= yeoman.app %&gt;/styles',
          cssDir: '.tmp/styles',
          generatedImagesDir: '.tmp/images/generated',
          imagesDir: '&lt;%= yeoman.app %&gt;/images',
          javascriptsDir: '&lt;%= yeoman.app %&gt;/scripts',
          fontsDir: '&lt;%= yeoman.app %&gt;/styles/fonts',
          importPath: './bower_components',
          httpImagesPath: '/images',
          httpGeneratedImagesPath: '/images/generated',
          httpFontsPath: '/styles/fonts',
          relativeAssets: false,
          assetCacheBuster: false,
          raw: 'Sass::Script::Number.precision = 10\n'
        },
        dist: {
          options: {
            generatedImagesDir: '&lt;%= yeoman.dist %&gt;/images/generated'
          }
        },
        server: {
          options: {
            debugInfo: true
          }
        }
      },
  </code></pre>