I have a grunt file as shown below. The problem I am having is when I change the contents of a .scss file, grunt watch sass does not trigger a refresh. Is there something obvious that I am doing wrong?
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
build : {
dest: '_site'
},
sass: {
dist: {
options: {
style: 'compressed',
trace: true
},
files: {
'css/main.css': '_scss/main.scss',
'css/ie8.css': '_scss/ie8.scss',
'css/ie9.css': '_scss/ie9.scss'
}
}
},
shell: {
jekyllBuild: {
command: 'jekyll build'
},
jekyllServe: {
command: 'jekyll serve'
}
},
watch: {
files: ['_layouts/*.html', '*.md', '*.yml'],
// SASS watch does not work :(
sass: {
files: ['_scss/**/*.scss'],
tasks: ['sass:dist'] // This should be sass'
}
}
});
grunt.loadNpmTasks('grunt-contrib-sass');
grunt.loadNpmTasks('grunt-shell');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-jekyll');
// Compiles SASS, Builds Jekyll, and Serves Jekyll.
grunt.registerTask('default', ['sass:dist', 'shell:jekyllBuild', 'shell:jekyllServe']);
}
Also when I change a .scss file, the terminal indicates that a file has been changed but grunt watch sass does not run.
Regenerating: 1 file(s) changed at 2015-08-05 13:14:50 ...done in 0.017384 seconds.
EDIT:
I figured it out. What I was attempting to do was use grunt to watch my sass files and re-compile when changes were made. I also wanted jekyll to serve & watch the html files for changes. These things cannot be ran concurrently which was what I was attempting to do. I did happen to find a helper called 'load-grunt-tasks' which allows for concurrent tasks to be ran by adding the following code to the gruntfile:
concurrent: {
serve: [
'sass',
'watch',
'shell:jekyllServe'
],
options: {
logConcurrentOutput: true
}
},
// Then register the following tasks
// Register the grunt serve task
grunt.registerTask('serve', ['concurrent:serve']);
// Then run the following from the terminal:
grunt serve
At first some general troubleshooting:
Did you made sure all dependencies are properly installed? npm install
Are all dependencies up to date? npm update
I see that you're using Jekyll, why do you introduce Grunt at this point? Jekyll comes with its own watch task. This may produce some errors.
watch: {
files: ['_layouts/*.html', '*.md', '*.yml'],
// SASS watch does not work :(
sass: {
files: ['_scss/**/*.scss'],
tasks: ['sass:dist']
}
}
This looks kinda broken to me. What is watch supposed to do with files: [...]? There is no task to be executed while watching over these files. You don't have any grunt tasks which would modify .html, .md or .yml files, so why do you even list them?
Apart from that, it looks fine to me.
Is there a reason that you're using Grunt for this? Jekyll comes with a perfectly fine Sass watcher, and if you want to carry out any further pre/post-processing tasks you can do so using Jekyll's plugin system.
You can place your .scss/.sass files in _sass, and call them from a .scss/.sass file located anywhere else that starts with some YAML frontmatter.
A common structure would be something like this:
- _scss/
- normalize.scss
- typography.scss
- [whatever].scss
- assets/
- main.scss
With assets/main.scss containing the following:
---
# You just need these --- lines to tell Jekyll to parse this file.
---
#import "normalize";
#import "typography";
#import [...]
// Other styles too
body {
background-color: #f00;
color: {{ site.branding.color }}; // Can even use Jekyll variables
}
As far as plugins go, I'm using octopress-autoprefixer to automatically prefix CSS3 properties. The process for using this plugin is as follows:
gem install octopress-autoprefixer
Add this to your _config.yml:
gems:
- octopress-autoprefixer
That's it.
Now when you make any changes to your Sass, after the CSS files are generated in _site/, autoprefixer will do it's magic to them.
Related
I would like to use normalize.scss with my project that's currently set up with Grunt to compile the SCSS using Compass.
I've found this, and have installed it using the command below (from here: https://www.npmjs.com/package/node-normalize-scss)
npm install node-normalize-scss --save-dev
Underneath that are config examples for gulp and grunt, but not for compass. I have tried using:
includePaths: require('node-normalize-scss').includePaths
And adding that to my Compass options in my GruntFile.js, but I get an error that starts a little like this:
Running "compass:dev" (compass) task
Error: invalid option: --include-paths=/Applications/MAMP/htdocs/homepagev2/node_modules/node-normalize-scss
Usage: compass compile [path/to/project] [path/to/project/src/file.sass ...] [options]
Description:
compile project at the path specified or the current directory if not specified.
After that I read that I can use a simple command to import that path so that in my .scss I can #import "normalize"
importPath: 'node_modules/node-normalize-scss/',
But using this I get an error saying
>> File "styles/sass/style.scss" changed.
Local Npm module "node-normalize-scss" not found. Is it installed?
But it appears to be compilling normalize.scss into css, so I'm guessing it's kind of working.
Is there a better solution so I don't get the error on compile?
Thank you.
I, too, had this problem, and eventually found the answer on here: https://github.com/gruntjs/grunt-contrib-compass
The option to use for compass (which takes completely different options to sass) is importPath, which you've found, and it works the same way.
So, importPath: require('node-normalize-scss').includePaths should, hopefully, work for you.
This is my current Gruntfile.js in full:
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
compass: {
dist: {
options: {
importPath: require('node-normalize-scss').includePaths,
sassDir: 'path/to/sass',
cssDir: 'path/to/css'
}
}
},
watch: {
css: {
files: '**/*.scss',
tasks: ['compass']
}
}
});
grunt.loadNpmTasks('grunt-contrib-compass');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.registerTask('default',['watch']);
}
I'm trying to create a very simple build system with Grunt in windows using Cygwin to handle compiling,concatenation and minification of my scss/css and coffee/js files.
I'm having problem with Grunt not recognizing Sass as a command.
I should note that the same Gruntfile, same tasks, same packages is working perfectly on linux (why of course!) and this problem is solely related to implementing the same system on Windows.
I have correctly installed Ruby and Sass (both "ruby -v" and "sass -v" work as expected) and i have no problem compiling scss into css from command line
$ sass --update sass:css
and it effectively converts all the .scss files into .css
Grunt itself works without problems, compiling coffee into js, concatenating js or css files, minifying them and watching for changes.
here is the complete Gruntfile.js, for reference
module.exports = function(grunt) {
grunt.initConfig({
concat: {
js: {
src: 'js/*.js',
dest: 'build/js/scripts.js',
},
css: {
src: 'css/*.css',
dest: 'build/css/theme.css',
},
},
uglify: {
jsMin : {
files: {
'build/js/scripts.min.js' : ['build/js/scripts.js']
},
},
},
cssmin: {
styleMin : {
files : {
'build/css/theme.min.css' : ['build/css/theme.css']
},
},
},
watch: {
jsW: {
files: ['js/**/*.js'],
tasks: ['concat:js','uglify:jsMin'],
},
cssW: {
files: ['css/**/*.css'],
tasks: ['concat:css','cssmin'],
},
sassW: {
files: ['sass/**/*.scss'],
tasks: ['exec']
}
},
exec: {
Sass : 'sass --update sass:css',
Coffee : 'coffee -o js/ -c coffee/'
}
});
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.loadNpmTasks('grunt-exec');
grunt.registerTask('default',['exec','concat','uglify','cssmin','watch']);
};
if then I start grunt it displays the following alert
Running "exec:Sass" (exec) task
'sass' is not recognized as an internal or external command, operable program or batch file.
Exited with code: 1.
Warning: Task "exec:Sass" failed. Use --force to continue.
Aborted due to warnings.
as I stated before the system works perfectly on linux, so I would guess there is something wrong with my Paths, but why then would sass work fine from command line and not being recognized through grunt?
last thing I would like to point out is that, during some digging and testing to try and guess what the problem was before posting here on SO, I found out that calling out any bash function that has not an .exe file in cygwin/bin shows the same error
http://i.stack.imgur.com/DGLe5.png (testing on files 'sass' 'sdoc' and 'ruby.exe')
modified grunt-exec for testing:
exec: {
Sass : 'sass -v',
Ruby : 'ruby -v',
Sdoc : 'sdoc -v',
}
and they showed the following after grunt --force
http://i.stack.imgur.com/3boy7.png
while from normal command-line
$ sass -v && ruby -v && sdoc -v
Sass 3.4.16 (Selective Steve)
ruby 2.0.0p598 (2014-11-13) [x86_64-cygwin]
4.2.0
I seriously have no idea where to go from here, any help would be appreciated.
I still haven't found a solution to my problem.
However I did find a workaround that works just fine, just in case someone is interested or is having the same issue I had.
the solution involves running sass directly through Ruby (which my grunt-exec task recognize), so I edited my Gruntfile.js as follows :
exec: {
Sass : 'ruby sass.rb'
}
which calls a sass.rb file in the main directory, which is a ruby script file.
require "sass"
options = {
:syntax => :scss,
:style => :compressed,
:load_paths => ['./src/sass/']
# load_paths is required in case your 'master.scss' files use #import to attach other scss files
}
render = Sass::Engine.new(File.read("src/sass/master.scss"), options).render
File.write("src/css/master.css", render)
You can find further options in the SASS documentation
I know this is not an actual answer to my question, but this is the only thing the worked right away without any problem. I'll still try to figure out why the more common solutions (grunt-contrib-sass and grunt-exec) won't work, but with this workaround I have my build system up and running.
For a project I am using SASS 3.2.19 and Compass 0.12.5 combined with the last version of Grunt.
My file structure looks like this :
styles/
css/
page1.css
page2.css
page3.css
...
sass/
page1.scss
page2.scss
page3.scss
...
generics/
_general.scss
_menu.scss
_ie.scss
...
partials/
_sectionBegin.scss
_sectionClients.scss
...
In each pages{number}.scss file I import the scss blocks I actually need like this :
#import "generics/general"; // inside this file _ie.scss is imported
#import "generics/menu";
#import "partials/sectionBegins";
#import "partials/sectionClients";
.additionalStyles {
background: url(/example/example-cover.jpg) no-repeat;
}
And finally, here is my Gruntfile.js :
compass: {
dev: {
options: {
sassDir: ['styles/sass'],
cssDir: ['styles/css'],
outputStyle: 'expanded',
noLineComments: true,
environment: 'development'
}
},
...
grunt.registerTask('default', ['compass:dev' , 'watch']);
So, what I am doing here is setting Grunt to watch the sass/ repository. As soon as it detects some changes the page.css will be overwrite.
Well, this project structure actually works perfectly when there are only a few pages but now that I have more than 40 pages the compilation time is taking approximately 1min.
Indeed supposed that I edit a .scss file which is used by all the pages, all the pages will have to be overwritten.
So, what I am missing here ? How can I improve my project file structure and do you have some good examples of a gruntfile conf in a similar scenario ?
We also have a Sass project with a lot of partials. We still haven't figured out what to do when modifying a partial that is used by a lot of .scss files; there really isn't a way to get around having to compile all of them (eventually, when you deploy; sometimes you're only working on one page and really do only need one to compile in the short term). You could set up grunt tasks to compile each of your pages individually so you at least have something to run when you only need to compile a single .scss file.
The best thing to do in your case might be to think outside the box here...what if that partial WASN'T required by a lot of .scss files? What if it was only imported into one main.scss file that compiled into a minified main.css that was included on every page of your project (as the first script on the page, so its styles would get overwritten by any more specific page styles)? We have one script that includes our generic styles for things like buttons, forms, panels...stuff that's on pretty much every page, and isn't too large a burden to load in on pages that don't have a form or a button, especially if minified.
For the cases where modifying a partial only needs to prompt compilation of a few Sass files, we have figured out a solution using the Gruntfile. You can use grunt-contrib-watch to run different tasks depending on where a change was detected. For example, we have the following 2 tasks set up for grunt-contrib-sass:
sass: {
dev_mainstyles: {
options: {
sourcemap: true,
trace: true,
style: 'expanded',
compass: true,
lineNumbers: true
},
files: {
'...css/main.css': '...sass/main.scss',
},
},
dev_customerstyles: {
options: {
sourcemap: true,
trace: true,
style: 'expanded',
compass: true,
lineNumbers: true
},
files: [{
expand: true,
cwd: '.../sass/',
src: ['customers/**/*.scss'],
dest: '.../css/',
ext: '.css'
}],
},
}
I have set up the following tasks for grunt-contrib-watch:
watch: {
sassmain: {
files: ['.../sass/*.scss'],
tasks: ['sass:dev_mainstyles'],
},
sasscustomers: {
files: ['.../sass/customers/**/*.scss'],
tasks: ['sass:dev_customerstyles'],
},
}
By listing both files and directories you can get as specific as you need to and hopefully you'll be able to set up watch tasks that only compile what is needed whenever something changes! Good luck!
We're still looking for suggestions on how to make this whole process even faster, by the way, this is by no means a definitive answer, it's just some tricks we've figured out so far.
Here is my Gruntfile.js
watch: {
options: { livereload: true },
compass: {
files: ['assets/sass/*.{scss,sass}'],
tasks: ['compass']
},
// js: {
// files: '<%= jshint.all %>',
// tasks: ['jshint', 'uglify']
// },
livereload: {
// files: ['*.html', '*.php', 'assets/stylesheets/**/*.{css}']
files: ['*.html', '*.php', 'assets/stylesheets/custom.css']
}
},
// compass and scss
compass: {
dist: {
options: {
config: 'config.rb',
force: true
}
}
},
and this is output from grunt watch :
Done, without errors.
... Reload assets/sass/custom.scss ...
... Reload assets/stylesheets/custom.css ...
Completed in 11.033s at Fri Dec 06 2013 14:20:48 GMT+0100 (CET) - Waiting...
OK
>> File "assets/stylesheets/custom.css" changed.
>> File "assets/sass/custom.scss" changed.
Running "compass:dist" (compass) task
overwrite assets/stylesheets/custom.css (0.701s)
identical assets/stylesheets/app.css (3.452s)
Compilation took 4.158s
Done, without errors.
... Reload assets/sass/custom.scss ...
... Reload assets/stylesheets/custom.css ...
Completed in 10.719s at Fri Dec 06 2013 14:21:53 GMT+0100 (CET) - Waiting...
..so, why is livereload taking so much time for refreshing the page,
10secs to preview any change in my .scss file, also how it would be
possible not to refresh page completely but only inject .css changes
in page?
..another thing i would like to know is how to avoid that
compilation lag on app.css, which took almost 4 secs, and it is not
even changed?
I am using livereload browser extension with this configuration.
Thanks.
1a: to speed things up in a watch task try the option spawn:false. This might make things unstable, but it's worth a try. If it seems ok go for it. It might cause you problems later though if you add a lot of different tasks to the watch task. But you can worry about that then and disable it potentially.
1b:
First of all don't enable livereload on for the compass task. (you have it globally, take in only in the css) Because of this it will trigger a livereload event for the scss file as well. But since the livereload client doesn't know this file then it will reload the whole page. Make sure the only reported file is the compiled css.
Secondly the watch task will trigger livereload for previously changed files as well. This is a known but, I believe it is fixed in master, but no published yet.
https://github.com/gruntjs/grunt-contrib-watch/issues/205
2:
Well it have to compile it to compare it, then it just reports that it is identical.
To only inject .css changes:
watch: {
compass: {
files: ['assets/sass/*.{scss,sass}'],
tasks: ['compass']
},
livereload: {
files: ['assets/stylesheets/*.css'],
options: { livereload: true }
}
}
Unfortunately, I am also getting slow and similar compilation times (it must be compass).
Using terminal to compile my sass/compass works perfectly, Ive used it for a few projects now and have started using compass plugins within these projects. However I also need to start automating my projects using GRUNT but I havent been able to get compass plugins to work with the GRUNT sass plugin "grunt-contrib-sass".. I dont have to use this plugin its just the first I found - does anyone know how to get this to work or suggest another plugin?
All help is very much appreciated..
• I want to use GRUNT to automate some tasks including the processing of my SASS/Compass.
Problem:
• I have a compass plugin called "rgbapng" as seen in my config file that causes GRUNT to error out (as seen in the last image)
Question:
• How to I get this compass plugin to work with GRUNTS "grunt-contrib-sass" - has anyone else done this - has anyone a suggested plugin that works better?
Compass Config.rb file...
The settings Im using in my grunt.js file for grunt-contrib-sass
The Error im getting in returnwatch/
UPDATE: updated grunt file now get a different error message see below
The last error was fixed by changing the paths in the gruntfile.js from /assets/ to assets/ .. however the scss now compiles with no errors but the plugin still doesn't work..
use grunt-compass, sass compiling is included.
Required plugins go in require array and import statements in your sass code.
Dont forget to install the gem you need.
compass:
app:
options:
require: ['compass-h5bp', 'ceaser-easing'] #to use compass libs
sassDir: 'assets/css'
cssDir: 'assets/css'
imagesDir: 'assets/img'
fontsDir: 'assets/font'
httpPath: "/"
relativeAssets: true
boring: true
debugInfo: true
outputStyle: 'compressed'
raw: 'preferred_syntax = :sass\n'
js code:
compass: {
app: {
options: {
require: ['compass-h5bp', 'ceaser-easing'],
sassDir: 'assets/css',
cssDir: 'assets/css',
imagesDir: 'assets/img',
fontsDir: 'assets/font',
httpPath: "/",
relativeAssets: true,
boring: true,
debugInfo: true,
outputStyle: 'compressed',
raw: 'preferred_syntax = :sass\n'
}
}
}