I'm using the postcss plugin for grunt (https://github.com/nDmitry/grunt-postcss), where I use cssnano for minification as following:
postcss: {
test: {
src: [
'dist/**/*.css'
],
options: {
map: true,
failOnError: true,
processors: [
require('autoprefixer')({
overrideBrowserslist: ['last 1 version']
}),
require('cssnano')()
]
},
},
When there are some errors during minification I get that in the grunt output, but I don't get what file caused the error:
How can I make grunt to show me the file that caused it to fail ?
Related
can you please take a look at the following Gruntfile to see if you can determine why it isn't running cssnano and autoprefixer?
Grunt is currently watching my project and with each save grunt-sass compiles fine but neither grunt-cssnano or autoprefixer are doing their thing and no errors are reported.
Done, without errors.
Completed in 1.906s at Wed Nov 25 2015 13:12:18 GMT+0000 (GMT Standard Time) - Waiting...
File "sass\styles.scss" changed.
Running "sass:dist" (sass) task
I figure I've done something wrong with grunt-contrib-watch setup (specifically the css part) but that's just a guess.
My project folder looks like so
dist
css
styles.css
node_modules (includes all relevant packages)
sass
styles.css
Gruntfile.js
package.json
And my Gruntfile is as follows
module.exports = function (grunt) {
grunt.initConfig({
sass: {
options: {
sourceMap: false
},
dist: {
files: {
'dist/css/styles.css': 'sass/styles.scss'
}
}
},
postcss: {
options: {
map: {
inline: false,
annotation: 'dist/css/maps/'
},
processors: [
require('autoprefixer')({
browsers: 'last 2 versions'
}),
require('cssnano')()
]
},
dist: {
src: 'dist/css/styles.css'
}
},
watch: {
sass: {
files: 'sass/*.scss',
tasks: ['sass']
},
css: {
files: 'dist/css/styles.css',
tasks: ['cssnano', 'autoprefixer']
}
},
});
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-sass');
grunt.loadNpmTasks('grunt-postcss');
grunt.loadNpmTasks('grunt-cssnano');
grunt.registerTask('default', ['watch', 'sass', 'postcss:dist', 'cssnano', 'autoprefixer']);
};
registering a task like you do :
grunt.registerTask('default', ['watch', 'sass', 'postcss:dist', 'cssnano']);
will execute the tasks one by one. So in your case, only the watch task will be executed because it "never ends" till you finish it. So the sass, postcss:dist, cssnano wont be reached.
So in your case it will execute the watch task only, which will watch the *.scss files to execute the sass task and watch the style.css to execute the cssnano and autoprefixer task.
But these 2 last tasks aren't defined in your config, so it won't do anything.
To solve your problem, remove the tasks from your default registered task because they aren't used :
grunt.registerTask('default', ['watch']);
And add a config for each missing task. for example:
cssnano: {
options: {
sourcemap: true
},
dist: {
files: {
'dist/css/styles.min.css': 'dist/css/styles.css'
}
}
},
//and same for autoprefixer
With a lot more trial and error it looks like I have a solution. The below file now runs Sass, cssnano, autoprefix and watch. Sass, cssnano and autoprefix packets (and I assume any others that are added in future) will do their thing in grunt.initConfig while and at the bottom of the file registerTask takes care of watch.
More work is need to figure out how to create other registerTasks but that's for another day.
Thanks to Mian who set me on the right track.
module.exports = function (grunt) {
grunt.initConfig({
sass: {
options: {
sourceMap: false
},
dist: {
files: {
'dist/css/styles.css': 'sass/styles.scss'
}
}
},
postcss: {
options: {
map: {
inline: false,
annotation: 'dist/css/maps/'
},
processors: [
require('autoprefixer')({
browsers: 'last 2 versions'
}),
require('cssnano')()
]
},
dist: {
src: 'dist/css/styles.css'
}
},
watch: {
sass: {
files: 'sass/*.scss',
tasks: ['sass', 'postcss']
},
},
});
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-sass');
grunt.loadNpmTasks('grunt-postcss');
grunt.loadNpmTasks('grunt-cssnano');
grunt.registerTask('default', ['watch']);
};
I use grunt-contrib-less with grunt-contrib-watch to compile my less files automatically upon change.
When the css is not present, grunt compiles it ok. When a css already exists and watch sees the less file changed, the css file is not modified. I have to remove it every time and let grunt recreate it with the modifications.
less config:
less: {
options: {
banner: '<%= meta.banner %>'
},
dev: {
options: {
sourceMap: true,
sourceMapFileInline: true,
compress: true
},
src: '<%= meta.dev.less %>/main.less',
dest: '<%= meta.prod.css %>/main.css'
},
prod: {
options: {
plugins: [
new( require( 'less-plugin-clean-css' ) )( {
'advanced': true,
'compatibility': 'ie9'
} )
],
},
src: '<%= meta.dev.less %>/main.less',
dest: '<%= meta.prod.css %>/main.css'
}
},
I'm under Windows 10 and every user have the rights to modifiy/delete the files in my dist folder.
How can I let grunt modify the css file?
EDIT
watch config
watch: {
options: {
livereload: 6325
},
js: {
files: [ '<%= meta.dev.js %>/main.js', '<%= meta.dev.js %>/plugins/*.js' ],
tasks: [ 'newer:concat' ]
},
images: {
files: '<%= meta.dev.img %>/**/*.{png,jpg,gif,svg}',
tasks: [ 'newer:imagemin' ]
},
css: {
files: '<%= meta.dev.less %>/**/*.less',
tasks: [ 'newer:less:dev' ]
}
}
Registration
grunt.registerTask( 'default', [ 'less:dev', 'concat', 'imagemin', 'copy', 'watch' ] );
Grunt output (verbose)
>> File "dev\less\elements\menu.less" changed.
Initializing
Command-line options: --verbose
Reading "Gruntfile.js" Gruntfile...OK
Registering Gruntfile tasks.
Reading package.json...OK
Parsing package.json...OK
Initializing config...OK
Loading "Gruntfile.js" tasks...OK
+ default, prod
Running tasks: newer:less:dev
Loading "grunt-newer" plugin
Registering "D:\[...]\static\node_modules\grunt-newer\tasks" tasks.
Loading "newer.js" tasks...OK
+ any-newer, newer, newer-clean, newer-postrun
Running "newer:less:dev" (newer) task
Options: cache="D:\\[...]\\static\\node_modules\\grunt-newer\\.cache", override=undefined
Files: dev/less/main.less -> dist/css/main.css
No newer files to process.
Here's what happens:
you modify menu.less
watch detects that and runs newer:less:dev
less:dev uses file main.less as only source (not menu.less)
that file hasn't changed, so newer concludes it doesn't need to run the task again
I suppose main.less includes menu.less, but newer doesn't know it.
So my suggested fix would be to get rid of the newer part.
Have you added correct watch config for less ?
watch: {
less: {
files: ['less/**/*.less'], // which files to watch
tasks: ['less'],
options: {
nospawn: true
}
}
}
To run grunt with your profile : grunt.registerTask('myprofile', ['less:dev', 'watch']);
While developing, I'm using karma and grunt to watch for file changes and run the tests.
In command line, I'd like to be able to simply enter
$ grunt watch
and have the karma server to start once, and thereafter having grunt watching for changes and running the various tasks (including karma tests) whenever files change. I don't want to enter $ karma start .
How can this be achieved?
Option #1
One can use the atBegin option of grunt-contrib-watch. The idea is to introduce a startup task, which will run at the startup of the watcher:
watch: {
startup: {
files: [], // This is redundant, but we get an error if not specifying files.
tasks: [ 'karma:continuous:start' ],
options: {
atBegin: true,
spawn: false
}
},
...
}
The full Gruntfile.js:
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
karma: {
options: {
files: [ 'client/**/*.spec.js' ],
frameworks: [ 'jasmine' ],
reporters: [ 'progress' ],
browsers: [ 'PhantomJS' ],
singleRun: true,
autoWatch: false
},
continuous: {
singleRun: false,
background: true
}
},
concat: { ... },
uglify: { ... },
watch: {
startup: {
files: [], // This is redundant, but we get an error if not specifying files.
tasks: [ 'karma:continuous:start' ],
options: {
atBegin: true,
spawn: false
}
},
js: {
files: [ '<%= concat.js.src %>' ],
tasks: [ 'concat:js', 'uglify' ]
},
karma: {
files: [ '<%= concat.js.src %>', 'src/**/test/**/*.js' ],
tasks: [ 'karma:continuous:run' ]
},
}
});
require('load-grunt-tasks')(grunt);
grunt.registerTask( 'default', [ 'concat', 'uglify', 'karma:unit:run' ] );
};
Option #2
As shown in this and this blogs, an alternative is instead of calling
$ grunt watch
one creates another task that launch the karma server:
grunt.registerTask( 'serve', [ 'karma:continuous:start', 'watch' ] );
and then calls:
$ grunt serve
The full Gruntfile.js:
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
karma: {
options: {
configFile: 'karma.conf.js'
},
unit: {
singleRun: true
},
continuous: {
// keep karma running in the background
background: true
}
},
concat: { ... },
uglify: { ... },
watch: {
js: {
files: [ '<%= concat.js.src %>' ],
tasks: [ 'concat:js', 'uglify' ]
},
karma: {
files: [ '<%= concat.js.src %>', 'src/**/test/**/*.js' ],
tasks: [ 'karma:continuous:run' ]
},
}
});
require('load-grunt-tasks')(grunt);
grunt.registerTask( 'default', [ 'concat', 'uglify', 'karma:unit:run' ] );
grunt.registerTask( 'serve', [ 'karma:continuous:start', 'watch' ] );
};
I have multiple jshint configurations in my gruntfile.
I tested each configuration, and it works great.
However, when I define a target in the gruntfile for each configuration, jshint stops working and all I can see is :
0 files linted. Please check your ignored files.
This is how my jshint configuration looks like with targets:
jshint: {
backend: {
options: {
jshintrc: '.jshintrc'
},
all: [
'Gruntfile.js',
'server.js',
'*.js',
'backend/{,*/}*.js'
]
},
test: {
options: {
jshintrc: 'test.jshintrc'
},
all: [
'test/{,*/}*.js'
]
}
}
For multiple tasks changing:
'all' : {...}
to
'files': { src: [...] }
should fix it. It would seem that 'all' is a shorthand for a single task, with multiple tasks, jshint will be looking for files in files->src ie:
backend: {
options: {
jshintrc: '.jshintrc'
},
'files': {
'src': [
'Gruntfile.js',
'server.js',
'*.js',
'backend/{,*/}*.js'
]
}
},
test: {
options: {
jshintrc: 'test.jshintrc'
},
'files': {
'src': [
'test/{,*/}*.js'
]
}
}
My team found out this works, we are using it on a project of ours.
Even though I don't recommend using this method, it taught me something about how grunt works, and how you can programatically invoke tasks and change options at runtime so I find it relevant.
jshint: {
options: {
jshintrc: '.jshintrc'
},
all: [
'Gruntfile.js',
'<%= yeoman.app %>/scripts/{,*/}*.js'
],
backend: [
'server.js'
]
},
....
grunt.registerTask('backend', function() {
grunt.config.set('jshint.options.jshintrc', '.backendhintrc');
grunt.task.run('jshint:backend');
});
So I'm making my own Wordpress Framework, and am utilizing grunt and sass. I'm newer at grunt and sass, but experienced enough with grunt to kind of know what I'm doing, but I've used LESS in the past and not Sass.
I'm taking the Gruntfile.js file from roots.io as a starting point. Everything I have is correct as far as I know, but I'm not too sure about a couple of things. I removed the js stuff because I'm not going to be watching for it, and I added grunt-contrib-sass.
When running grunt watch I get this error:
grunt watch
/Gruntfile.js:22
watch: {
^^^^^
Loading "Gruntfile.js" tasks...ERROR
>> SyntaxError: Unexpected identifier
Warning: Task "watch" not found. Use --force to continue.
Aborted due to warnings.
Below is my Gruntfile.js and my package.json
Gruntfile.JS
'use strict';
module.exports = function (grunt) {
grunt.initConfig({
version: {
options: {
file: 'lib/scripts.php',
css: 'assets/css/main.min.css',
cssHandle: 'su_styles'
}
},
sass: {
dist: {
options: {
style: 'compressed'
},
files: {
'assets/css/main.min.css': [
'assets/scss/app.scss'
]
}
}
},
watch: {
sass: {
files: [
'assets/scss/*.scss',
'assets/scss/foundation/*.scss'
],
tasks: ['sass', 'version']
},
livereload: {
// Browser live reloading
// https://github.com/gruntjs/grunt-contrib-watch#live-reloading
options: {
livereload: false
},
files: [
'assets/css/main.min.css',
'templates/*.php',
'*.php'
]
}
},
clean: {
dist: [
'assets/css/main.min.css'
]
}
});
// Load tasks
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-wp-version');
grunt.loadNpmTasks('grunt-contrib-sass');
// Register tasks
grunt.registerTask('default', [
'clean',
'version',
'sass'
]);
grunt.registerTask('dev', [
'watch'
]);
};
package.json - with some stuff taken out to preserve a bit of privacy
{
"name": "sudoh",
"version": "1.0.0",
"author": "Brandon Shutter <brandon#brandonshutter.com>",
"licenses": [
{
"type": "MIT",
"url": "http://opensource.org/licenses/MIT"
}
],
"engines": {
"node": ">= 0.10.0"
},
"devDependencies": {
"grunt": "~0.4.1",
"grunt-contrib-clean": "~0.5.0",
"grunt-contrib-watch": "~0.5.3",
"grunt-wp-version": "~0.1.0",
"grunt-contrib-sass": "~0.5.0"
}
}
Thanks for your help ahead of time.
It seems there wasn't anything wrong with my setup. My code editor (Brackets) added hidden characters for whatever reason and was causing a syntax error. Switching over to Sublime and saving the file again allowed it work perfectly.
Thanks for the help everyone.