Template var in gruntfile doesn't always work - gruntjs

In my gruntfile I noticed that I can't always get a template variable to work. Below is a very simple small grunt file to show the issue. The copy task will understand <%= yeoman.app %>, but the less task does not.
I suppose this has something to do with the files syntax, but I dont understand why. Can someone elaborate? And.. how can I get less to work?
'use strict';
module.exports = function (grunt) {
require('load-grunt-tasks')(grunt);
var yeomanConfig = {
app: 'app',
dist: 'dist'
};
grunt.initConfig({
yeoman: yeomanConfig,
copy: {
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.app %>',
dest: '<%= yeoman.dist %>',
src: '404.html'
}]
}
},
less: {
dist: {
files: {
'<%= yeoman.dist %>/styles/main.css': ['<%= yeoman.app %>/styles/main.less']
}
}
}
});
};
grunt copy: works
grunt less: Warning: An error occurred while processing a template (_ is not defined). Use --force to continue.
note, I'm using grunt 0.4.2 and node 0.10.13

Related

Grunt | Compile subfolders + including pug files

In this current situation grunt does watch the files in subfolder but there is no compilation to dist.
See (part) of my gruntfile:
grunt.initConfig({
pkg: grunt.file.readJSON('./package.json'),
config: {
dist: './dist',
src: './src',
htmlPath: '<%= config.dist %>'
},
watch: {
options: {
spawn: false
},
pug: {
files: '<%= config.src %>/**/*.pug',
tasks: ['pug:dist']
}
},
pug: {
dist: {
options: {
pretty: true,
data: {
debug: false
}
},
files: [{
expand: true,
cwd: '<%= config.src %>',
src: ['*.pug'],
dest: '<%= config.dist %>',
ext: '.html',
}]
}
},
});
I am guessing this probally because of includes folders and such (that should appear in dist folder). How can I modify my setup so grunt does compile some specific subfolders and files within?

Looping grunt-watch with new version of autoprefixer

Up until recently I've been using a similar gruntfile to this with success. However in my latest project grunt watch is looping continually - sometimes 4 times, sometimes 15 times or so before stopping - I can't figure out how to change the gruntfile to get it working properly again.
module.exports = function (grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
// Define our source and build folders
js_path: 'public_html/js',
img_path: 'public_html/img',
css_path: 'public_html/css',
imagemin: {
dynamic: {
files: [{
expand: true,
cwd: '<%= img_path %>/',
src: ['*.{png,jpg,gif}'],
dest: '<%= img_path %>/'
}]
}
},
concat: {
dist: {
src: [
'<%= js_path %>/jquery-ui.js',
'<%= js_path %>/plugin_royal_slider.js',
'<%= js_path %>/plugins.js',
'<%= js_path %>/plugin_selectboxit.js',
'<%= js_path %>/plugin_picturefill.js',
'<%= js_path %>/plugin_jquery_placeholder.js',
'<%= js_path %>/plugin_pickadate.js',
'<%= js_path %>/script.js'
],
dest: '<%= js_path %>/output.js',
nonull: true
}
},
jshint: {
beforeconcat: [
'<%= js_path %>/jquery-ui.js',
'<%= js_path %>/plugin_royal_slider.js',
'<%= js_path %>/plugins.js',
'<%= js_path %>/plugin_selectboxit.js',
'<%= js_path %>/plugin_picturefill.js',
'<%= js_path %>/plugin_jquery_placeholder.js',
'<%= js_path %>/plugin_pickadate.js',
'<%= js_path %>/script.js'],
afterconcat: ['<%= js_path %>/output.js'
],
options: {
sub: true,
"-W004": true,
"-W041": true,
"-W093": true,
"-W032": true,
"-W099": true,
"-W033": true,
"-W030": true,
ignores: ['<%= js_path %>/jquery-ui.js']
}
},
uglify: {
options: {
banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy H:M:s") %> */\n',
mangle: true,
compress: {drop_console: true} // true supresses console.log output: https://github.com/gruntjs/grunt-contrib-uglify#turn-off-console-warnings
},
dist: {
files: {
'<%= js_path %>/js.min.js': ['<%= js_path %>/output.js']
}
}
},
postcss: {
options: {
map: true,
processors: [
require('autoprefixer')({browsers: 'last 2 versions'}),
require('csswring')
]
},
dist: {
src: '<%= css_path %>/*.css'
}
},
watch: {
options: {nospawn: true},
scripts: {
files: ['<%= js_path %>/*.js'],
tasks: ['build']
},
css: {
files: ['<%= css_path %>/*.css'],
tasks: ['build']
},
grunt: {
files: ['Gruntfile.js']
}
}
});
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-imagemin');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-postcss');
grunt.registerTask('build', ['jshint', 'concat', 'uglify', 'postcss']); // run manually with grunt build or run grunt watch - ctrl c to exit
grunt.registerTask('optimg', ['imagemin']); // run with grunt optimg
grunt.event.on('watch', function (action, filepath) {
grunt.log.writeln(filepath + ' has ' + action);
});
};
Current dependencies:
"grunt": "~0.4.5",
"grunt-contrib-concat": "~0.5.1",
"grunt-contrib-imagemin": "~0.9.4",
"grunt-contrib-jshint": "~0.11.2",
"grunt-contrib-uglify": "~0.9.1",
"grunt-contrib-watch": "~0.6.1",
"grunt-postcss": "~0.6.0",
"csswring": "~4.0.0",
"autoprefixer-core": "~6.0.1",
"autoprefixer": "~6.0.3"
your issue is that concat generates its file into your js_path directory, and watch monitors all js files in that directory. So what happens is:
you modify a js source file
watch detects your modification and launches concat
concat generates output.js
watch detects output.js and launches concat
3 then 4 repeat - until you're saved by watch buffering (which prevents triggering too quickly in sequence)
To solve it, you have to remove the concat output from the watchlist.
What I recommend is to have concat output to a build directory outside your sources - it's best practice to separate build artefacts from source elements anyway. Define a build_path config variable and use it in your concat target.
If you really can't do that for a good reason, manually remove output.js from the watch with a negative directive (http://gruntjs.com/configuring-tasks#globbing-patterns):
watch: {
scripts: {
files: ['<%= js_path %>/*.js', '!<%= js_path %>/output.js'],
tasks: ['build']
},
}
Moving the postcss to a separate task has solved the problem for me.
Here are the changes to the gruntfile:
watch: {
options: {nospawn: true},
scripts: {
files: ['<%= js_path %>/*.js'],
tasks: ['build_js']
},
css: {
files: ['<%= css_path %>/*.css'],
tasks: ['build:css']
},
grunt: {
files: ['Gruntfile.js']
}
and
grunt.registerTask('build_js', ['jshint', 'concat', 'uglify']);
grunt.registerTask('build_css', ['postcss:dist']);

LESS/Grunt is not writing the sourcemap reference to the end of the compiled CSS

I am using grunt-contrib-less to compile my .less files in to a single CSS stylesheet. Everything is working, except the source map, which I cannot get to work under any circumstances!
Here is my Gruntfile:
'use strict';
module.exports = function(grunt) {
// Force use of Unix newlines
grunt.util.linefeed = '\n';
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
project: {
// Add entries to this array to create variables for use by Grunt
app: ['app'],
server: 'http://mysite.app',
// Components
bower: ['<%= project.app %>/bower_components'],
bootstrap: ['<%= project.bower %>/bootstrap'],
// Custom Assets
assets: ['<%= project.app %>/assets'],
css: ['<%= project.assets %>/css'],
less: ['<%= project.assets %>/less'],
js: ['<%= project.assets %>/js']
},
less: {
production: {
options: {
ieCompat: true,
sourceMap: true,
sourceMapFilename: '<%= project.css %>/style.css.map',
sourceMapURL: '<%= project.server %>/assets/css/style.css.map',
sourceMapBasepath: 'app',
sourceMapRootpath: '<%= project.server %>'
},
files: {
'<%= project.css %>/style.css': '<%= project.less %>/style.less'
}
}
},
autoprefixer: {
dist: {
files: {
'<%= project.assets %>/css/style.css': '<%= project.assets %>/css/style.css'
}
}
},
concat: {
options: {
separator: ';\n',
sourceMap: true
},
plugins_head: {
// Add further Javascript plugins to this array and they will be
// concatenated in to the plugins-built-head.js file
src: [
'<%= project.bower %>/modernizr/modernizr.js'
],
dest: '<%= project.js %>/built/plugins-built-head.js'
},
plugins: {
// Add further Javascript plugins to this array and they will be
// concatenated in to the plugins-built.js file
src: [
'<%= project.bootstrap %>/js/dropdown.js'
],
dest: '<%= project.js %>/built/plugins-built.js'
},
custom: {
// Add further custom-written javascript files to this array and
// they will be concatenated in to the scripts-built.js file
src: [
'<%= project.js %>/scripts.js'
],
dest: '<%= project.js %>/built/scripts-built.js'
}
},
watch: {
css: {
files: [
'<%= project.bootstrap %>/less/*.less',
'<%= project.less %>/*.less'
],
tasks: [
'less',
'autoprefixer'
],
options: {
livereload: true
}
},
js: {
files: [
'<%= project.js %>/scripts.js'
],
tasks: ['concat']
},
html: {
files: [
'<%= project.app %>/*.html'
],
options: {
livereload: true
}
}
}
});
grunt.loadNpmTasks('grunt-run-grunt');
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-autoprefixer');
grunt.registerTask('default', [
'watch'
]);
};
What's happening is that Grunt is writing a proper and correct style.css.map file, but it's not writing the following line to the end of the compiled style.css file:
/*# sourceMappingURL=http://mysite.app/assets/css/style.css.map */
That's the one line that's missing. Everything else is getting compiled and written correctly. If I manually add that line to the end of the compiled CSS, Chrome picks up on the source map properly, but it's not being written in.
Additionally, trying options like sourceMapFileInline seems to make no difference - the file is never written inline.
Any ideas?
Hopefully you have found a solution by now. This is for other people with the same issue:
Make sure the soourcemap will be placed in the same folder as css.
Set sourceMapUrl to only the name of the map file.
This will add the following line to your .css file: /*# sourceMappingURL=default.css.map */
Here are the sourcemap settings in my grunt file:
sourceMap: true,
sourceMapFilename: "src/assets/css/default.css.map",
sourceMapURL: "default.css.map"

Referring to Grunt targets resulting in Warning: Object true has no method 'indexOf'

My Code:
'use strict';
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
//Define paths
js_src_path: 'webapp/js',
js_build_path: 'webapp/js',
css_src_path: 'webapp/css',
css_build_path: 'webapp/css',
less_src_path: 'webapp/less',
less_build_path:'webapp/less',
//Convert Less to CSS and minify if compress = true
less: {
development: {
options: {
path: ['<%= less_src_path %>'],
},
files: {
//'<%= less_build_path %>/app.css':'<%= concat.less.dest %>',
//Dynamic expansion 1:1
expand: true,
cwd: '<%= less_src_path %>',
dest: '<%= less_build_path %>',
src: '*.less',
ext: '.less.css'
}
},
production: {
options: {
path: ['<%= less_src_path %>'],
//compress: true
yuicompress: true
},
files: {
//'<%= less_build_path %>/app.css':'<%= concat.less.dest %>',
//Dynamic expansion 1:1
expand: true,
cwd: '<%= less_src_path %>',
dest: '<%= less_build_path %>',
src: '*.less',
ext: '.less.min.css'
}
}
}
});
// Load the plugin that provides the tasks.
grunt.loadNpmTasks('grunt-lib-contrib');
grunt.loadNpmTasks('grunt-contrib-less');
// Task(s).
grunt.registerTask('les', ['less']);
grunt.registerTask('proless', ['less:production']);
grunt.registerTask('devless', ['less:devevelopment']);
};
Running each of the following:
grunt les
grunt proless
grunt devless
Results in:
Warning: Object true has no method 'indexOf' Use --force to continue
If I remove the task development:{ ... } and production: { .... } and leave the interior and just change my les call to hit less it works fine.
I ran into a similar problem with contrib-concat. I think it's a syntax error on both our parts.
Try adding an array literal around your development target's "files" property, like so:
files: [{
//'<%= less_build_path %>/app.css':'<%= concat.less.dest %>',
//Dynamic expansion 1:1
expand: true,
cwd: '<%= less_src_path %>',
dest: '<%= less_build_path %>',
src: '*.less',
ext: '.less.css'
}]
Here's the doc: http://gruntjs.com/configuring-tasks#building-the-files-object-dynamically
Hope that helps!

grunt-requirejs - how to optimize CSS?

I'm using Yeoman, and are trying to setup requirejs to optimise my CSS files.
I have this in my Gruntfile.js:
requirejs: {
css: {
options: {
optimizeCss: 'standard',
cssIn: 'app/styles/main.css',
out: 'app/styles/main.min.css'
}
}
}
When I run the build command I get an error:
grunt build
Running "requirejs:css" (requirejs) task
>> Error: TypeError: new path must be a string
>> at Object.fs.renameSync (fs.js:439:18)
Warning: Task "requirejs:css" failed
I'm not really sure what's happening there, or how to debug that.
Does anyone know what the problem could be?
Never mind, I worked it out.
The silly useminPrepare task that ships with Yeoman stuffs around with the grunt-requirejs configuration. Kind of annoying, esp. since the point of me wanting to use grunt-requirejs was because I didn't like how usemin worked to begin with.
UPDATE:
This is my configuration that works:
//index.html:
<!-- build:js scripts/scripts.js -->
<script data-main="scripts/main" src="components/requirejs/require.js"></script>
<!-- endbuild -->
//Gruntfile.js:
requirejs: {
js: {
options: {
baseUrl: '<%= yeoman.tmp %>/scripts',
out: '<%= yeoman.dist %>/scripts/scripts.js',
name: 'main',
optimize: 'none',
mainConfigFile: '<%= yeoman.app %>/scripts/main.js',
useStrict: true,
wrap: true
}
},
css: {
options: {
optimizeCss: 'standard',
cssIn: '<%= yeoman.app %>/styles/main.css',
out: '<%= yeoman.dist %>/styles/main.css'
}
}
},
useminPrepare: {
html: '<%= yeoman.app %>/index.html',
options: {
dest: '<%= yeoman.dist %>'
}
},
usemin: {
html: '<%= yeoman.dist %>/index.html',
options: {
dirs: ['<%= yeoman.dist %>']
}
}
grunt.registerTask('build', [
'requirejs:js',
'requirejs:css',
'useminPrepare', //must be after requirejs:css as it breaks its config params
'usemin'
]);
NOTE: There is still an underlying bug in grunt-usemin where it (incorrectly) tries to alter the requirejs config for the requirejs:css configuration. I've reported that here

Resources