I'm using grunt 0.4.2 and grunt-contrib-less 0.9.0. I want my LESS to be compiled into CSS with support for source maps.
My LESS files are in public/less, and the main one is called main.less.
The compiling of public/less/main.less into public/css/main.css works, but source maps don't work.
What is wrong with my Grunt config below?
{
less: {
dev: {
options: {
compress: true,
yuicompress: true,
optimization: 2,
sourceMap: true,
sourceMapFilename: "public/css/main.css.source-map.json", //Write the source map to a separate file with the given filename.
sourceMapBasepath: "public/less", //Sets the base path for the Less file paths in the source map.
sourceMapRootpath: "/"//Adds this path onto the Less file paths in the source map.
},
files: {
"public/css/main.css": "public/less/main.less"
}
}
},
watch: {
styles: {
files: ["public/less/*"],
tasks: ['less'],
options: {
livereload: true,
nospaces: true
}
}
}
}
I don't want to have my CSS created in my /public/less folder; I want to put it into /public/css. Otherwise, I could use this other config, which works:
{
less: {
dev: {
options: {
compress: true,
yuicompress: true,
optimization: 2,
sourceMap: true,
sourceMapFilename: "public/less/main.css.map", //I DO NOT WANT THE CSS MAP HERE
sourceMapBasepath: "public/less", //Sets the base path for the Less file paths in the source map.
},
files: {
"public/less/main.css": "public/less/main.less"//I DO NOT WANT THE CSS HERE
}
}
},
watch: {
styles: {
files: ["public/less/*"],
tasks: ['less'],
options: {
livereload: true,
nospaces: true
}
}
}
}
I found the LESS site documentation to be more clear regarding params used by grunt-contrib-less.
LESS: Command Line Usage
http://lesscss.org/usage/#command-line-usage-installing-lessc
NPM: grunt-contrib-less
https://www.npmjs.org/package/grunt-contrib-less
File structure:
laravel/gruntfile.js
laravel/public/less/main.less
laravel/public/css/main.css
laravel/public/css/main.css.map
File 'main.css.map' note:
If you wish, you can rename to: main.css.source-map.json
I guess you have some server rule setup that doesn't server *.map files properly from the 'css' folder
Compression notes:
cleancss: true = will remove sourceMappingURL comment from main.css
yuicompress: true = will NOT remove sourceMappingURL comment from main.css
Gruntfile.js
less: {
dev: {
options: {
compress: true,
yuicompress: true,
optimization: 2,
sourceMap: true,
sourceMapFilename: 'public/css/main.css.map', // where file is generated and located
sourceMapURL: '/css/main.css.map', // the complete url and filename put in the compiled css file
sourceMapBasepath: 'public', // Sets sourcemap base path, defaults to current working directory.
sourceMapRootpath: '/', // adds this path onto the sourcemap filename and less file paths
},
files: {
'public/css/main.css': 'public/less/main.less',
}
}
},
watch: {
styles: {
files: ["public/less/*"],
tasks: ['less'],
options: {
livereload: true,
nospaces: true
}
}
},
laravel/public/css/main.css
.class{ compiled css here } /*# sourceMappingURL=/css/main.css.map */
laravel/public/css/main.css.map
{"version":3,"sources":["/less/main.less"], etc...
If you're still having trouble with it try setting the SourceMapURL to the full path, for example:
http://www.yourdomain.com/assets/css/styles.css.map
Obviously this is a bit of a pain as it's not relative, so when you move your site it will need to be changed. I had the same issue as you and this got it working for me.
Another point I discovered is that you cannot load the SourceMaps from the file system. It has to be from a web server. To get around the file system issue I believe you can inline the SourceMap.
This thread on GitHub has a lot of information.
https://github.com/less/less.js/issues/1050#issuecomment-25621390
Related
I'd like to make configuration of grunt tasks a bit easier. Currently I've got a lot of different configuration files, like a .csslintrc, jshintrc, bower.json and so on.
It would be really cool if I could concatenate all these configuration files into one single file. This configuration file could look something like
{
"csslint": {
"important": 1,
// ...
},
"jshint": {
//...
},
"bower": {
//...
}
}
My only solution so far would be using a preprocessor and simply insert the options in the tasks (I couldn't figure out how to insert options otherwise). But this doesn't seem to be a very beautiful way...
Most (all?) grunt tasks let you define options in the Gruntfile itself instead of their respective .*rc files.
So if you do that, you nearly get your one single configuration file for free.
For example:
jshint: {
dist: {
options: {
curly: true,
eqeqeq: true,
},
src: ['path/to/**/*.js']
}
},
csslint: {
dist: {
options: {
import: 2
},
src: ['path/to/**/*.css']
}
},
bower: {
install: {
options: {
targetDir: './lib',
layout: 'byType',
install: true,
verbose: false,
cleanTargetDir: false,
cleanBowerDir: false,
bowerOptions: {}
}
}
}
Hi everyone,
I have a lot of css files in my project with a very complex structure so I had to replicate the structure of the folders containing css files at the root of the project.
So every time I save a scss file, grunt has to check each 160+ lines of config I gave him.
Is there a way to optimize this this configuration? Maybe an option to tell contrib-sass to compile the scss file with the same structure he's in?
Here is a simplified example of my code :
...
sass: {
dist: {
options: {
style: 'expanded',
sourcemap: 'none',
trace: true,
},
files: {
'./css/laptop.css': './scss/css/laptop.scss',
....
... (160 more lines)
....
'./css/player.css': './scss/css/player.scss'
}
}
},
...
Thanks!
You can pass parameters to your Grunt task using grunt.option. Take a look.
You can pass params to grunt using this syntax:
$grunt [task] myparam=myvalue
Then, from any place in your gruntfile (or sub-files) you can do that:
var myoption = grunt.option("myparam") || defaultvalue;
With that, you can create a task for compile only one scss file passing the name in the param for example or even if the param doesn't exist compile all.
...
var myoption = grunt.option("myparam") || defaultvalue;
sass: {
dist: {
options: {
style: 'expanded',
sourcemap: 'none',
trace: true,
},
files: {
if ( myoption == defaultvalue ) {
'./css/laptop.css': './scss/css/laptop.scss',
....
... (160 more lines)
....
'./css/player.css': './scss/css/player.scss'
} else {
}
}
}
},
...
After some research I discovered grunt-newer which can be used this way:
css:{
files: [
'./scss/**'
],
tasks: ['newer:sass'],
livereload: {
options: { livereload: true },
files: ['./**'],
},
}
It's not what I was trying to do exactly but It optimised perfectly the grunt process.
Really nice plugin!!
Hi Grunt concat doesn't shows errors, but it doesn't concentrate my styles.css file. Here is a screenshot of it:
link: http://i.imgur.com/gHlbROe.png
And here is a screenshot of my css file, which still isn't being concatenated(also you can see my folder structure here below):
link: http://i.imgur.com/UlGWQv1.png
And here is my gruntfile.js (Maybe I should have a different separator in concat_css.):
module.exports = function(grunt) {
grunt.initConfig({
less: {
development: {
options: {
compress: true,
yuicompress: true,
optimization: 2,
css: ['concat']
},
files: {
"css/styles.css": "css/styles.less" // destination file and source file
}
}
},
concat_css: {
options: {
// Task-specific options go here.
separator: '}'
},
all: {
src: ["css/styles.css"],
dest: "css/styles.css"
},
},
watch: {
styles: {
files: ['css/styles.less'], // which files to watch
tasks: ['less', 'concat_css'],
options: {
nospawn: true
}
}
}
});
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-concat-css');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.registerTask('default', ['less', 'watch', 'concat_css']);
};
I'm pretty sure the task is called concat, not concat_css. You're config will need to match that name (that is, you should not be using concat_css at all). Aside from that, why would you make the separator the closing brace (})? If you ever have more than one file that will almost certainly cause a syntax error in the concatenated CSS file. I would leave out that option unless you have a specific need for it.
concat: { // <-- change this to match the name of the task: "concat"
all: {
src: ["css/styles.css"],
dest: "css/styles.css"
},
},
I am trying to achieve a smooth workflow.
my problem:
My JS modifications are shown and minified and the live reload works fine. When I make changes to my SCSS files they do not run under the run command:
grunt
or the grunt plugin:
grunt watch
It only works when I invoke:
grunt sass
This was the output from the 'grunt sass' console window:
Macintosh:grunt-test Neil$ grunt sass
Running "sass:dist" (sass) task
File "css/global.css" created.
Done, without errors.
Notes:
When I run 'grunt watch' on a sass file I have noticed that grunt runs the minification on the javascript for no reason. Surely this be invoked when that file or one of its dependencies is effected?
Gruntfile.js Contents:
module.exports = function(grunt) {
// 1. All configuration goes here
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
watch: {
options: {
files: ['css/*.css'],
livereload: true
},
css: {
files: ['css/*.scss'],
tasks: ['sass'],
options: {
spawn: false,
}
},
scripts: {
files: ['js/*.js', 'scss/*.scss'],
tasks: ['concat', 'uglify'],
options: {
spawn: false,
}
}
},
sass: {
dist: {
options: {
style: 'compressed'
},
expand: true,
cwd: 'scss/',
src: ['*.scss'],
dest: 'css/',
ext: '.css'
}
},
concat: {
// 2. Configuration for concatinating files goes here.
dist: {
src: [
'js/libs/*.js', // All JS in the libs folder
'js/global.js' // This specific file
],
dest: 'js/build/production.js',
}
},
uglify: {
build: {
src: 'js/build/production.js',
dest: 'js/build/production.min.js'
}
},
imagemin: {
dynamic: {
files: [{
expand: true,
cwd: 'images-lossy/',
src: ['**/*.{png,jpg,gif}'],
dest: 'images/'
}]
},
png: {
options: {
optimizationLevel: 7
}
},
jpg: {
options: {
progressive: true
}
}
}
});
// 3. Where we tell Grunt we plan to use this plug-in.
// CONCATENATION PLUGIN
grunt.loadNpmTasks('grunt-contrib-concat');
// MINIFY PLUGIN
grunt.loadNpmTasks('grunt-contrib-uglify');
// IMG CRUSH PLUGIN
grunt.loadNpmTasks('grunt-contrib-imagemin');
// GRUNT WATCH PLUGIN
grunt.loadNpmTasks('grunt-contrib-watch');
// SASS LIBARY PLUGIN
grunt.loadNpmTasks('grunt-contrib-sass');
// 4. Where we tell Grunt what to do when we type "grunt" into the terminal.
grunt.registerTask('default', ['sass','concat', 'uglify', 'imagemin', 'watch']);
};
I hope the above information helps. I have previously used Codekit, and it a really great app. I want to move to grunt but maybe my configuration file is incorrect I am close.
Any help would be greatly appreciated.
Neil
It looks like both of your issues occur within the watch configuration.
First, the reason the SASS task isn't working during watch is due to the files entry pointing to the wrong location. Your current files entry points to the "css" folder, but it should point to the "scss" folder, according to what you've specified in the actual "sass" task. In other words, your entry should be: files: ['scss/*.scss'].
css: {
files: ['scss/*.scss'],
tasks: ['sass'],
options: {
spawn: false,
}
}
Second, the JavaScript minification occurs during the watch whenever a SASS file changes because you have it listed here:
scripts: {
files: ['js/*.js', 'scss/*.scss'], // <-- scss is covered here
tasks: ['concat', 'uglify'],
options: {
spawn: false,
}
}
Change it to files: ['js/*.js'], instead to have the watch task kick in for JavaScript files only.
Once you address those issues, if things are slightly working you might want to expand the patterns so that it covers all files in the subdirectories for your JavaScript, CSS, SASS, etc. For example, js/*.js includes all .js files under the js folder, while js/**/*.js covers the js folder and its subfolders. You can read more under the GruntJS "globbing patterns" documentation.
EDIT: here's how the updated watch should look like...
watch: {
options: {
livereload: true
},
// css is really for Sass
css: {
files: ['scss/*.scss'],
tasks: ['sass'],
options: {
spawn: false,
}
},
// scripts will detect js changes
scripts: {
files: ['js/**/*.js'],
tasks: ['jshint', 'concat', 'uglify'],
options: {
spawn: false,
}
}
},
As mentioned, your individual tasks might need to use the ** pattern similar to what I've done with the "scripts" entry above: js/**/*.js
I've found this solution to building less using the grunt-contrib-less package, but I can't figure out using grunts configuration tasks (http://gruntjs.com/configuring-tasks) how to output the *.css files to a specific destination. I tried dest: "C:/my_folder/". Any suggestions?
less: {
options: {
paths: ['css/base']
},
// target name
src: {
// no need for files, the config below should work
expand: true,
cwd: "css/base",
src: "*.less",
ext: ".css"
}
}
I've also tried using the example from grunt-contrib-less but I can't figure out how to get it to a) just choose all the files and build them into the same file name with a different extension (ie. .less to .css) like it does above b) I don't understand the options JSON attribute (even reading the docs)
less: {
development: {
options: {
paths: ["assets/css"]
},
files: {
"dev/css/*.css": "dev/less/*.less"
}
},
production: {
options: {
paths: ["assets/css"],
cleancss: true
},
files: {
"prod/css/*.css": "dev/less/*.less"
}
}
}
At the end of all this I'd really like to have a combination of both of these that took all my less and compiles it to css for development and finally css for production which is minified.
I've thumbed through http://net.tutsplus.com/tutorials/javascript-ajax/meeting-grunt-the-build-tool-for-javascript/ and http://www.integralist.co.uk/Grunt-Boilerplate.html without much luck understanding Grunt.
You need to specify dest property. the best way to specify sources of less files is to use relative path.( relative Gruntfile.js )
less: {
options: {
paths: ['css/base']
},
// target name
src: {
expand: true,
cwd: "css/base",
src: "*.less",
ext: ".css"
dest: "build/" // Destination for your compiled css files.
}
}