How to make grunt sass preprocessor and livereload fast? - sass

I'm creating a project with project with SCSS. I have scaffolded a project with Yeoman and this far everything has worked fine. Now the SCSS preprocessor and livereload is extremely slow.
This is my Gruntfile.js watch task:
watch: {
sass: {
files: ['<%= yeoman.app %>/_/css/**/*.{scss,sass}'],
tasks: ['sass:server']
},
livereload: {
options: {livereload: true},
files: [
'<%= yeoman.app %>/_/css/**/*.css',
'<%= yeoman.app %>/_/css/*.css',
'<%= yeoman.app %>/_/js/**/*',
'<%= yeoman.app %>/script/*.js',
'<%= yeoman.app %>/_/img/**/*',
'<%= yeoman.app %>/*.php',
'<%= yeoman.app %>/**/*.php'
]
}
}
And this is my watch sass task:
sass: {
server: {
options: {
sourcemap: true,
debugInfo: true,
lineNumbers: true,
style: 'expanded'
},
files : [{
expand: true,
cwd: '<%= yeoman.app %>/_/css',
src: '**/*.scss',
dest: '<%= yeoman.app %>/_/css',
ext: '.css'
}]
},
dist: {
...
}
},
I have main.scss file where is most of my css. I tried to make another, smaller .scss file thinking that maybe smaller file loads faster. It is preprocessed almost instantly, but the page is livereloaded only after the main.scss is processed to main.css.
My questions are:
How should I arrange my Gruntfile.js to make livereload faster?
Why is the livereload not launched when smaller-file.scss is preprocessed and saved to disk as smaller-file.css?
How can I make my sass.server function so that it only processes the file which is edited, not all of the files set in the source?

Actually this wasn't about Gruntfile.js at all. I was importing the whole bootstrap on top of my main.scss, so obviously it takes a lot of time to preprocess that.
#import "../bower_components/bootstrap-sass-official/assets/stylesheets/_bootstrap.scss";
Now I just grab the parts of bootstrap I really need.

Related

Yeoman angular: Sass compilation extremly slow

I'm using the latest Yeoman angular generator to start a project. I'd like to use SASS and Compass, which is provided by default from Yeoman.
The big drawback of Compass is, that it is painfully slow. I have Twitter Bootstrap included (the SASS version), three .scss files in my styles folder and the compilation takes about 10-12 seconds. It is slightly faster (about one second) when using live watch.
But waiting 10-12 seconds on every style file change would be insane. I looked around and found some posts (most of them about a year old), but they didn't help me so much. I also found this project https://github.com/sindresorhus/grunt-sass where the original https://github.com/gruntjs/grunt-contrib-sass is replaced by a C++ version, instead of Ruby compiling. But the drawback is, that it doesn't support Compass.
I hope somebody can help me, to speed things up.
This is my setup:
I'm starting my grunt server with grunt serve, live watch *.js, *.scss files, and triggering a reload on file change. This is my Gruntfile.js:
// Generated on 2014-06-16 using generator-angular 0.9.0-1
'use strict';
// # Globbing
// for performance reasons we're only matching one level down:
// 'test/spec/{,*/}*.js'
// use this if you want to recursively match all subfolders:
// 'test/spec/**/*.js'
module.exports = function (grunt) {
// Load grunt tasks automatically
require('load-grunt-tasks')(grunt);
// Time how long tasks take. Can help when optimizing build times
require('time-grunt')(grunt);
// Configurable paths for the application
var appConfig = {
app: require('./bower.json').appPath || 'app',
dist: 'dist'
};
// Define the configuration for all the tasks
grunt.initConfig({
// Project settings
yeoman: appConfig,
// Watches files for changes and runs tasks based on the changed files
watch: {
bower: {
files: ['bower.json'],
tasks: ['wiredep']
},
js: {
files: ['<%= yeoman.app %>/scripts/{,*/}*.js'],
tasks: ['newer:jshint:all'],
options: {
livereload: '<%= connect.options.livereload %>'
}
},
jsTest: {
files: ['test/spec/{,*/}*.js'],
tasks: ['newer:jshint:test', 'karma']
},
compass: {
files: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
tasks: ['compass:server', 'autoprefixer'],
options: {
spawn: false,
}
},
gruntfile: {
files: ['Gruntfile.js']
},
livereload: {
options: {
livereload: '<%= connect.options.livereload %>'
},
files: [
'<%= yeoman.app %>/{,*/}*.html',
'.tmp/styles/{,*/}*.css',
'<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
]
}
},
// The actual grunt server settings
connect: {
options: {
port: 9000,
// Change this to '0.0.0.0' to access the server from outside.
hostname: 'localhost',
livereload: 35729
},
livereload: {
options: {
open: false,
middleware: function (connect) {
return [
connect.static('.tmp'),
connect().use(
'/bower_components',
connect.static('./bower_components')
),
connect.static(appConfig.app)
];
}
}
},
test: {
options: {
port: 9001,
middleware: function (connect) {
return [
connect.static('.tmp'),
connect.static('test'),
connect().use(
'/bower_components',
connect.static('./bower_components')
),
connect.static(appConfig.app)
];
}
}
},
dist: {
options: {
open: false,
base: '<%= yeoman.dist %>'
}
}
},
// Make sure code styles are up to par and there are no obvious mistakes
jshint: {
options: {
jshintrc: '.jshintrc',
reporter: require('jshint-stylish')
},
all: {
src: [
'Gruntfile.js',
'<%= yeoman.app %>/scripts/{,*/}*.js'
]
},
test: {
options: {
jshintrc: 'test/.jshintrc'
},
src: ['test/spec/{,*/}*.js']
}
},
// Empties folders to start fresh
clean: {
dist: {
files: [{
dot: true,
src: [
'.tmp',
'<%= yeoman.dist %>/{,*/}*',
'!<%= yeoman.dist %>/.git*'
]
}]
},
server: '.tmp'
},
// Add vendor prefixed styles
autoprefixer: {
options: {
browsers: ['last 1 version']
},
dist: {
files: [{
expand: true,
cwd: '.tmp/styles/',
src: '{,*/}*.css',
dest: '.tmp/styles/'
}]
}
},
// Automatically inject Bower components into the app
wiredep: {
app: {
src: ['<%= yeoman.app %>/index.html'],
ignorePath: new RegExp('^<%= yeoman.app %>/|../')
},
sass: {
src: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
ignorePath: /(\.\.\/){1,2}bower_components\//
}
},
// Compiles Sass to CSS and generates necessary files if requested
compass: {
options: {
sassDir: '<%= yeoman.app %>/styles',
cssDir: '.tmp/styles',
generatedImagesDir: '.tmp/images/generated',
imagesDir: '<%= yeoman.app %>/images',
javascriptsDir: '<%= yeoman.app %>/scripts',
fontsDir: '<%= yeoman.app %>/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: '<%= yeoman.dist %>/images/generated'
}
},
server: {
options: {
debugInfo: true
}
}
},
// Renames files for browser caching purposes
filerev: {
dist: {
src: [
'<%= yeoman.dist %>/scripts/{,*/}*.js',
'<%= yeoman.dist %>/styles/{,*/}*.css',
'<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
'<%= yeoman.dist %>/styles/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: '<%= yeoman.app %>/index.html',
options: {
dest: '<%= yeoman.dist %>',
flow: {
html: {
steps: {
js: ['concat', 'uglifyjs'],
css: ['cssmin']
},
post: {}
}
}
}
},
// Performs rewrites based on filerev and the useminPrepare configuration
usemin: {
html: ['<%= yeoman.dist %>/{,*/}*.html'],
css: ['<%= yeoman.dist %>/styles/{,*/}*.css'],
options: {
assetsDirs: ['<%= yeoman.dist %>','<%= yeoman.dist %>/images']
}
},
// The following *-min tasks will produce minified files in the dist folder
// By default, your `index.html`'s <!-- Usemin block --> will take care of
// minification. These next options are pre-configured if you do not wish
// to use the Usemin blocks.
// cssmin: {
// dist: {
// files: {
// '<%= yeoman.dist %>/styles/main.css': [
// '.tmp/styles/{,*/}*.css'
// ]
// }
// }
// },
// uglify: {
// dist: {
// files: {
// '<%= yeoman.dist %>/scripts/scripts.js': [
// '<%= yeoman.dist %>/scripts/scripts.js'
// ]
// }
// }
// },
// concat: {
// dist: {}
// },
imagemin: {
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.app %>/images',
src: '{,*/}*.{png,jpg,jpeg,gif}',
dest: '<%= yeoman.dist %>/images'
}]
}
},
svgmin: {
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.app %>/images',
src: '{,*/}*.svg',
dest: '<%= yeoman.dist %>/images'
}]
}
},
htmlmin: {
dist: {
options: {
collapseWhitespace: true,
conservativeCollapse: true,
collapseBooleanAttributes: true,
removeCommentsFromCDATA: true,
removeOptionalTags: true
},
files: [{
expand: true,
cwd: '<%= yeoman.dist %>',
src: ['*.html', 'views/{,*/}*.html'],
dest: '<%= yeoman.dist %>'
}]
}
},
// ngmin tries to make the code safe for minification automatically by
// using the Angular long form for dependency injection. It doesn't work on
// things like resolve or inject so those have to be done manually.
ngmin: {
dist: {
files: [{
expand: true,
cwd: '.tmp/concat/scripts',
src: '*.js',
dest: '.tmp/concat/scripts'
}]
}
},
// Replace Google CDN references
cdnify: {
dist: {
html: ['<%= yeoman.dist %>/*.html']
}
},
// Copies remaining files to places other tasks can use
copy: {
dist: {
files: [{
expand: true,
dot: true,
cwd: '<%= yeoman.app %>',
dest: '<%= yeoman.dist %>',
src: [
'*.{ico,png,txt}',
'.htaccess',
'*.html',
'views/{,*/}*.html',
'images/{,*/}*.{webp}',
'fonts/*'
]
}, {
expand: true,
cwd: '.tmp/images',
dest: '<%= yeoman.dist %>/images',
src: ['generated/*']
}, {
expand: true,
cwd: '.',
src: 'bower_components/bootstrap-sass-official/vendor/assets/fonts/bootstrap/*',
dest: '<%= yeoman.dist %>'
}]
},
styles: {
expand: true,
cwd: '<%= yeoman.app %>/styles',
dest: '.tmp/styles/',
src: '{,*/}*.css'
}
},
// Run some tasks in parallel to speed up the build process
concurrent: {
server: [
'compass:server'
],
test: [
'compass'
],
dist: [
'compass:dist',
'imagemin',
'svgmin'
]
},
// Test settings
karma: {
unit: {
configFile: 'test/karma.conf.js',
singleRun: false
}
}
});
grunt.loadNpmTasks('grunt-sass');
grunt.registerTask('serve', 'Compile then start a connect web server', function (target) {
if (target === 'dist') {
return grunt.task.run(['build', 'connect:dist:keepalive']);
}
grunt.task.run([
'clean:server',
'wiredep',
'concurrent:server',
'autoprefixer',
'connect:livereload',
'watch'
]);
});
grunt.registerTask('server', 'DEPRECATED TASK. Use the "serve" task instead', function (target) {
grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
grunt.task.run(['serve:' + target]);
});
grunt.registerTask('test', [
'clean:server',
'autoprefixer',
'connect:test',
'karma'
]);
grunt.registerTask('build', [
'clean:dist',
'wiredep',
'useminPrepare',
'concurrent:dist',
'autoprefixer',
'concat',
'ngmin',
'copy:dist',
'cdnify',
'cssmin',
'uglify',
'filerev',
'usemin',
'htmlmin'
]);
grunt.registerTask('default', [
'newer:jshint',
'test',
'build'
]);
};
When starting my grunt server, I get this ouput:
Running "serve" task
Running "clean:server" (clean) task
Cleaning .tmp...OK
Running "wiredep:app" (wiredep) task
Running "wiredep:sass" (wiredep) task
Running "concurrent:server" (concurrent) task
Running "compass:server" (compass) task
directory .tmp/styles/
create .tmp/styles/colors.css (0.173s)
create .tmp/styles/main.css (5.485s)
create .tmp/styles/styles.css (5.725s)
Compilation took 11.39s
Done, without errors.
Execution Time (2014-06-17 13:43:30 UTC)
compass:server 12.9s ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 100%
Total 12.9s
Running "autoprefixer:dist" (autoprefixer) task
File .tmp/styles/colors.css created.
File .tmp/styles/main.css created.
File .tmp/styles/styles.css created.
Running "connect:livereload" (connect) task
Started connect web server on http://localhost:9000
Running "watch" task
Waiting...
A file change shows this log:
>> File "app/styles/colors.scss" changed.
Running "compass:server" (compass) task
identical .tmp/styles/colors.css (0.033s)
overwrite .tmp/styles/main.css (4.074s)
overwrite .tmp/styles/styles.css (4.548s)
Compilation took 9.216s
Running "autoprefixer:dist" (autoprefixer) task
File .tmp/styles/colors.css created.
File .tmp/styles/main.css created.
File .tmp/styles/styles.css created.
Running "watch" task
Completed in 12.515s at Tue Jun 17 2014 15:48:47 GMT+0200 (CEST) - Waiting...
As you can see, the initial startup takes about 13 seconds, a file change about 9 seconds.
Any ideas, how to speed this up?
UPDATE
I played around a little bit, and this might help. It doesn't solve the slow compilation problem itselft, but it speeds up things:
If you don't need the Bootstrap SASS version, skip it and switch to the normal CSS version. Your compilation time will decrease significant
If you need the SASS version, have a look at the bootstrap.scss file (either in your bower_components/bootstrap-sass-official folder, or if you have downloaded it manually, where you put it). Maybe there are some components you don't need, so you can skip some files. In your main SCSS file, you would include bootstrap like this: #import "bootstrap-sass-official/vendor/assets/stylesheets/bootstrap.scss";. Look inside this file, and copy only the things you need into your main SCSS file (and be sure to change the paths).
Make sure that you use the #import statements properly. By default, everything that doesn't has a _ in front of the filename get's compiled and included by Grunt. Normally you would have one file like styles.scss for your whole application or if you want to seperate it several page1.scss, page2.scss... files. If you include other files like #import 'colors.scss'; make sure the filename is _colors.scss. Otherwise the colors.scss gets also compiled by Grunt and then compiled again because of the #import statement. This would slow down you compilation process.
But again, this are only work arounds and doesn't speed up the compilation itself. So, still searching for a solution.
You can replace compass with compass-mixins which is fully compatible with libsass and use compass-importer to update all the original compass #import's with the new ones.
When I migrated some compass projects to libsass I reduced the compilation time from ~30s to ~350ms.

Yeoman aborts from 'grunt server' because of compass (Windows 8)

Why won't grunt server properly watch/compile scss through compass
ENV:
I am using Windows 8 + Yeoman (generator-angular 0.6.0-rc.1)
I think the same problem on Github:
Does not seems to work with windows 8, 64bit
For Anyone that doesn't know how to answer my question, is there anything I might add, that you believe, would help lead someone to this answer? I'm actively watching this thread.
Compass is installed and works properly
after running Grunt server — the compass:watch command fails and aborts everything
If I grunt server --force everything works properly expect scss.
I'm not sure if paths are incorrect so i've linked my Gruntfile.js
// Generated on 2013-11-30 using generator-angular 0.6.0-rc.1
'use strict';
// # Globbing
// for performance reasons we're only matching one level down:
// 'test/spec/{,*/}*.js'
// use this if you want to recursively match all subfolders:
// 'test/spec/**/*.js'
module.exports = function (grunt) {
require('load-grunt-tasks')(grunt);
require('time-grunt')(grunt);
grunt.initConfig({
yeoman: {
// configurable paths
app: require('./bower.json').appPath || 'app',
dist: 'dist'
},
watch: {
coffee: {
files: ['<%= yeoman.app %>/scripts/{,*/}*.coffee'],
tasks: ['coffee:dist']
},
coffeeTest: {
files: ['test/spec/{,*/}*.coffee'],
tasks: ['coffee:test']
},
compass: {
files: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
tasks: ['compass:server', 'autoprefixer']
},
styles: {
files: ['<%= yeoman.app %>/styles/{,*/}*.css'],
tasks: ['copy:styles', 'autoprefixer']
},
livereload: {
options: {
livereload: '<%= connect.options.livereload %>'
},
files: [
'<%= yeoman.app %>/{,*/}*.html',
'.tmp/styles/{,*/}*.css',
'{.tmp,<%= yeoman.app %>}/scripts/{,*/}*.js',
'<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
]
}
},
autoprefixer: {
options: ['last 1 version'],
dist: {
files: [{
expand: true,
cwd: '.tmp/styles/',
src: '{,*/}*.css',
dest: '.tmp/styles/'
}]
}
},
connect: {
options: {
port: 9000,
// Change this to '0.0.0.0' to access the server from outside.
hostname: 'localhost',
livereload: 35729
},
livereload: {
options: {
open: true,
base: [
'.tmp',
'<%= yeoman.app %>'
]
}
},
test: {
options: {
port: 9001,
base: [
'.tmp',
'test',
'<%= yeoman.app %>'
]
}
},
dist: {
options: {
base: '<%= yeoman.dist %>'
}
}
},
clean: {
dist: {
files: [{
dot: true,
src: [
'.tmp',
'<%= yeoman.dist %>/*',
'!<%= yeoman.dist %>/.git*'
]
}]
},
server: '.tmp'
},
jshint: {
options: {
jshintrc: '.jshintrc',
reporter: require('jshint-stylish')
},
all: [
'Gruntfile.js',
'<%= yeoman.app %>/scripts/{,*/}*.js'
]
},
coffee: {
options: {
sourceMap: true,
sourceRoot: ''
},
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.app %>/scripts',
src: '{,*/}*.coffee',
dest: '.tmp/scripts',
ext: '.js'
}]
},
test: {
files: [{
expand: true,
cwd: 'test/spec',
src: '{,*/}*.coffee',
dest: '.tmp/spec',
ext: '.js'
}]
}
},
compass: {
options: {
sassDir: '<%= yeoman.app %>/styles',
cssDir: '.tmp/styles',
generatedImagesDir: '.tmp/images/generated',
imagesDir: '<%= yeoman.app %>/images',
javascriptsDir: '<%= yeoman.app %>/scripts',
fontsDir: '<%= yeoman.app %>/fonts',
importPath: '<%= yeoman.app %>/bower_components',
httpImagesPath: '/images',
httpGeneratedImagesPath: '/images/generated',
httpFontsPath: '/fonts',
relativeAssets: false
},
dist: {},
server: {
options: {
debugInfo: true
}
}
},
// not used since Uglify task does concat,
// but still available if needed
/*concat: {
dist: {}
},*/
rev: {
dist: {
files: {
src: [
'<%= yeoman.dist %>/scripts/{,*/}*.js',
'<%= yeoman.dist %>/styles/{,*/}*.css',
'<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
'<%= yeoman.dist %>/styles/fonts/*'
]
}
}
},
useminPrepare: {
html: '<%= yeoman.app %>/index.html',
options: {
dest: '<%= yeoman.dist %>'
}
},
usemin: {
html: ['<%= yeoman.dist %>/{,*/}*.html'],
css: ['<%= yeoman.dist %>/styles/{,*/}*.css'],
options: {
assetsDirs: ['<%= yeoman.dist %>']
}
},
imagemin: {
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.app %>/images',
src: '{,*/}*.{png,jpg,jpeg}',
dest: '<%= yeoman.dist %>/images'
}]
}
},
svgmin: {
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.app %>/images',
src: '{,*/}*.svg',
dest: '<%= yeoman.dist %>/images'
}]
}
},
cssmin: {
// By default, your `index.html` <!-- Usemin Block --> will take care of
// minification. This option is pre-configured if you do not wish to use
// Usemin blocks.
// dist: {
// files: {
// '<%= yeoman.dist %>/styles/main.css': [
// '.tmp/styles/{,*/}*.css',
// '<%= yeoman.app %>/styles/{,*/}*.css'
// ]
// }
// }
},
htmlmin: {
dist: {
options: {
/*removeCommentsFromCDATA: true,
// https://github.com/yeoman/grunt-usemin/issues/44
//collapseWhitespace: true,
collapseBooleanAttributes: true,
removeAttributeQuotes: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeOptionalTags: true*/
},
files: [{
expand: true,
cwd: '<%= yeoman.app %>',
src: ['*.html', 'views/*.html'],
dest: '<%= yeoman.dist %>'
}]
}
},
// Put files not handled in other tasks here
copy: {
dist: {
files: [{
expand: true,
dot: true,
cwd: '<%= yeoman.app %>',
dest: '<%= yeoman.dist %>',
src: [
'*.{ico,png,txt}',
'.htaccess',
'bower_components/**/*',
'images/{,*/}*.{gif,webp}',
'fonts/*'
]
}, {
expand: true,
cwd: '.tmp/images',
dest: '<%= yeoman.dist %>/images',
src: [
'generated/*'
]
}]
},
styles: {
expand: true,
cwd: '<%= yeoman.app %>/styles',
dest: '.tmp/styles/',
src: '{,*/}*.css'
}
},
concurrent: {
server: [
'coffee:dist',
'compass:server',
'copy:styles'
],
test: [
'coffee',
'compass',
'copy:styles'
],
dist: [
'coffee',
'compass:dist',
'copy:styles',
'imagemin',
'svgmin',
'htmlmin'
]
},
karma: {
unit: {
configFile: 'karma.conf.js',
singleRun: true
}
},
cdnify: {
dist: {
html: ['<%= yeoman.dist %>/*.html']
}
},
ngmin: {
dist: {
files: [{
expand: true,
cwd: '.tmp/concat/scripts',
src: '*.js',
dest: '.tmp/concat/scripts'
}]
}
},
uglify: {
dist: {
files: {
'<%= yeoman.dist %>/scripts/scripts.js': [
'<%= yeoman.dist %>/scripts/scripts.js'
]
}
}
}
});
grunt.registerTask('server', function (target) {
if (target === 'dist') {
return grunt.task.run(['build', 'connect:dist:keepalive']);
}
grunt.task.run([
'clean:server',
'concurrent:server',
'autoprefixer',
'connect:livereload',
'watch'
]);
});
grunt.registerTask('test', [
'clean:server',
'concurrent:test',
'autoprefixer',
'connect:test',
'karma'
]);
grunt.registerTask('build', [
'clean:dist',
'useminPrepare',
'concurrent:dist',
'autoprefixer',
'concat',
'ngmin',
'copy:dist',
'cdnify',
'cssmin',
'uglify',
'rev',
'usemin'
]);
grunt.registerTask('default', [
'jshint',
'test',
'build'
]);
};
Ok Finally have solved it. I have 2 versions of Ruby200 on my computer x64 and 32 bit. My System Enviroment Variables were set to x64; however, all my gems were installed in 32bit and this is why none of this worked. I hope this helps someone in the future.
I ran into the same issue so I uninstalled the 64 bit version of Ruby and installed a 32 bit version. I still got the same error. After further searching I found that after installing compass with "gem install compass" it actually installed a newer released version (sass-3.30.rc.2) then if I installed sass manually with "gem install sass" (sass-3.2.14)
So what fixed this for me was after installing compass using "gem install compass" I uninstalled sass using "gem uninstall sass" and then reinstalled with "gem install sass"
Compass works for me now.

Configure grunt-contrib-sass in Yeoman

As I want to use Bourbon, I'm looking forward to remove compass grunt task and use plain sass task, however for some reason it doesn't seems to compile my scss files.
I have the following directory structure:
yeomanApp/
app/
styles/
css/
scss/
My Gruntfile.js looks something like this:
...
grunt.initConfig({
...
sass: {
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.app %>/styles',
src: ['scss/{,*/}*.scss'],
dest: 'css',
ext: '.css'
}]
}
},
...
});
grunt.loadNpmTasks('grunt-contrib-sass');
grunt.registerTask('server', function (target) {
if (target === 'dist') {
return grunt.task.run(['build', 'connect:dist:keepalive']);
}
grunt.task.run([
'clean:server',
'concurrent:server',
'sass',
'autoprefixer',
'connect:livereload',
'watch',
]);
});
...
When running this task:
$ grunt sass
Running "sass:dist" (sass) task
Done, without errors.
However, my scss files are not compiled into app/styles/css.
What am I missing?
I think there's a problem:
dest: '<%= yeoman.app %>/styles/css',
and should work.

Change HTTP images path used by Compass

I'm using Yeoman with Compass to compile the bootstrap SASS files. My Yeoman app is not in the base directory of my web server, it's in a directory called "ui". I'm getting 404 not found for the bootstrap images because the CSS files are pointing to /images when they should be pointing to /ui/images. I've tried modifying the compass options in my Gruntfile as below but it doesn't seem to change anything in the generated CSS:
compass: {
options: {
sassDir: '<%= yeoman.app %>/styles',
cssDir: '.tmp/styles',
imagesDir: '<%= yeoman.app %>/images',
javascriptsDir: '<%= yeoman.app %>/scripts',
fontsDir: '<%= yeoman.app %>/styles/fonts',
importPath: '<%= yeoman.app %>/bower_components',
httpImagesPath: '/ui/images',
httpGeneratedImagesPath: '/ui/images/generated',
relativeAssets: false
},
dist: {},
server: {
options: {
debugInfo: true
}
}
},
It doesn't seem to make a difference if I set relativeAssets equal to true or false. Thanks for the help!
If your Yeoman app has been generated by generator-webapp and includes bootstrap 2.x.x, you can see the following code in app/styles/main.scss.
$iconSpritePath: "../images/glyphicons-halflings.png";
$iconWhiteSpritePath: "../images/glyphicons-halflings-white.png";
You can modify these paths as you like.

What is workflow in Yeoman to work with Sass files?

I try to use yeoman but I don't know how to use my own sass files with it.
With
grunt server
Sass files are watched and compiled into
.tmp/styles/
But there is no reference to the compiled stylesheet, except <link rel="stylesheet" href="styles/main.css">
So, what is the recommended way to use the compiled sass files in index.html during development?
E.g. grunt server, if I change my style app/styles/my.sass into .tmp/styles/my.css, this is overwritten and it is outside the server (localhost:9000). Therefore, it is impossible to link it in index.html.
With grunt build is everything within main.css include my.sass but during the development I don't know how to use my own sass files in index.html.
Can you give me some simple example?
It is default yeoman installation. I did this:
yo angular test
I add app/styles/style.sass
grunt server this compile style.sass into .tmp/styles/style.css
now I don't know how to include style.css it in html
(sorry may be this is a stupid question but I am new in yeoman and grunt also)
This is Gruntfile.js from yeoman:
'use strict';
var lrSnippet = require('grunt-contrib-livereload/lib/utils').livereloadSnippet;
var mountFolder = function (connect, dir) {
return connect.static(require('path').resolve(dir));
};
module.exports = function (grunt) {
// load all grunt tasks
require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);
// configurable paths
var yeomanConfig = {
app: 'app',
dist: 'dist'
};
try {
yeomanConfig.app = require('./component.json').appPath || yeomanConfig.app;
} catch (e) {}
grunt.initConfig({
yeoman: yeomanConfig,
watch: {
coffee: {
files: ['<%= yeoman.app %>/scripts/{,*/}*.coffee'],
tasks: ['coffee:dist']
},
coffeeTest: {
files: ['test/spec/{,*/}*.coffee'],
tasks: ['coffee:test']
},
compass: {
files: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
tasks: ['compass']
},
livereload: {
files: [
'<%= yeoman.app %>/{,*/}*.html',
'{.tmp,<%= yeoman.app %>}/styles/{,*/}*.css',
'{.tmp,<%= yeoman.app %>}/scripts/{,*/}*.js',
'<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp}'
],
tasks: ['livereload']
}
},
connect: {
livereload: {
options: {
port: 9000,
// Change this to '0.0.0.0' to access the server from outside.
hostname: 'localhost',
middleware: function (connect) {
return [
lrSnippet,
mountFolder(connect, '.tmp'),
mountFolder(connect, yeomanConfig.app)
];
}
}
},
test: {
options: {
port: 9000,
middleware: function (connect) {
return [
mountFolder(connect, '.tmp'),
mountFolder(connect, 'test')
];
}
}
}
},
open: {
server: {
url: 'http://localhost:<%= connect.livereload.options.port %>'
}
},
clean: {
dist: ['.tmp', '<%= yeoman.dist %>/*'],
server: '.tmp'
},
jshint: {
options: {
jshintrc: '.jshintrc'
},
all: [
'Gruntfile.js',
'<%= yeoman.app %>/scripts/{,*/}*.js'
]
},
karma: {
unit: {
configFile: 'karma.conf.js',
singleRun: true
}
},
coffee: {
dist: {
files: {
'.tmp/scripts/coffee.js': '<%= yeoman.app %>/scripts/*.coffee'
}
},
test: {
files: [{
expand: true,
cwd: '.tmp/spec',
src: '*.coffee',
dest: 'test/spec'
}]
}
},
compass: {
options: {
sassDir: '<%= yeoman.app %>/styles',
cssDir: '.tmp/styles',
imagesDir: '<%= yeoman.app %>/images',
javascriptsDir: '<%= yeoman.app %>/scripts',
fontsDir: '<%= yeoman.app %>/styles/fonts',
importPath: '<%= yeoman.app %>/components',
relativeAssets: true
},
dist: {},
server: {
options: {
debugInfo: true
}
}
},
concat: {
dist: {
files: {
'<%= yeoman.dist %>/scripts/scripts.js': [
'.tmp/scripts/{,*/}*.js',
'<%= yeoman.app %>/scripts/{,*/}*.js'
]
}
}
},
useminPrepare: {
html: '<%= yeoman.app %>/index.html',
options: {
dest: '<%= yeoman.dist %>'
}
},
usemin: {
html: ['<%= yeoman.dist %>/{,*/}*.html'],
css: ['<%= yeoman.dist %>/styles/{,*/}*.css'],
options: {
dirs: ['<%= yeoman.dist %>']
}
},
imagemin: {
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.app %>/images',
src: '{,*/}*.{png,jpg,jpeg}',
dest: '<%= yeoman.dist %>/images'
}]
}
},
cssmin: {
dist: {
files: {
'<%= yeoman.dist %>/styles/main.css': [
'.tmp/styles/{,*/}*.css',
'<%= yeoman.app %>/styles/{,*/}*.css'
]
}
}
},
htmlmin: {
dist: {
options: {
/*removeCommentsFromCDATA: true,
// https://github.com/yeoman/grunt-usemin/issues/44
//collapseWhitespace: true,
collapseBooleanAttributes: true,
removeAttributeQuotes: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeOptionalTags: true*/
},
files: [{
expand: true,
cwd: '<%= yeoman.app %>',
src: ['*.html', 'views/*.html'],
dest: '<%= yeoman.dist %>'
}]
}
},
cdnify: {
dist: {
html: ['<%= yeoman.dist %>/*.html']
}
},
ngmin: {
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.dist %>/scripts',
src: '*.js',
dest: '<%= yeoman.dist %>/scripts'
}]
}
},
uglify: {
dist: {
files: {
'<%= yeoman.dist %>/scripts/scripts.js': [
'<%= yeoman.dist %>/scripts/scripts.js'
],
}
}
},
copy: {
dist: {
files: [{
expand: true,
dot: true,
cwd: '<%= yeoman.app %>',
dest: '<%= yeoman.dist %>',
src: [
'*.{ico,txt}',
'.htaccess',
'components/**/*',
'images/{,*/}*.{gif,webp}'
]
}]
}
}
});
grunt.renameTask('regarde', 'watch');
// remove when mincss task is renamed
grunt.renameTask('mincss', 'cssmin');
grunt.registerTask('server', [
'clean:server',
'coffee:dist',
'compass:server',
'livereload-start',
'connect:livereload',
'open',
'watch'
]);
grunt.registerTask('test', [
'clean:server',
'coffee',
'compass',
'connect:test',
'karma'
]);
grunt.registerTask('build', [
'clean:dist',
'jshint',
'test',
'coffee',
'compass:dist',
'useminPrepare',
'imagemin',
'cssmin',
'htmlmin',
'concat',
'copy',
'cdnify',
'usemin',
'ngmin',
'uglify'
]);
grunt.registerTask('default', ['build']);
};
What you are looking for is documented on: https://github.com/yeoman/grunt-usemin
Simply wrap your css imports in a comment block similarly to the way it's done with the javascript files
<!-- build:css styles/main.css -->
<link rel="stylesheet" href="styles/base.css">
<link rel="stylesheet" href="styles/modules.css">
<link rel="stylesheet" href="styles/layout.css">
<!-- endbuild -->
make sure your generator is up to date and your grunt tasks are all set. The one doing the magic is 'useminPrepare'
The actual magic for development is happening in
mountFolder(connect, '.tmp'),
for the connect-livereload middleware for grunt-contrib-watch.
This makes the local server also serve the contents of the .tmp folder, which is why you can reference styles/main.css and get .tmp/styles/main.css in return.
useminPrepare is usually never called in the server task.
You just include it like
<link rel="stylesheet" href="styles/style.css">
Yeoman/grunt will know when running the server that it should grab the sass file from the temp folder.

Resources