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?
I'm building a website with Bootstrap using less. I use grunt to automate the tasks.
In my gruntfile.js I have this part:
less: {
compileCore: {
options: {
strictMath: true,
sourceMap: true,
outputSourceFiles: true,
sourceMapURL: '<%= pkg.name %>.css.map',
sourceMapFilename: 'dist/css/<%= pkg.name %>.css.map'
},
src: 'less/bootstrap.less',
dest: 'dist/css/<%= pkg.name %>.css'
},
compileBrandingStyles: {
options: {
strictMath: true,
sourceMap: false,
outputSourceFiles: false
},
src: 'less/branding/**/*.less',
dest: 'dist/css/<%= what do I put here? %>.css'
}
},
In "compileBrandingStyles" I would like to fetch all *.less files in a folder and compile them into seperate css files with their original file names. No concatenation.
In the folder: less/branding I have x number of .less files:
theme-1.less
theme-2.less
theme-3.less
theme-4.less
I would like to output them in the dist/css/ folder like this:
theme-1.css
theme-2.css
theme-3.css
theme-4.css
So how should I write this part to keep their file names?
dest: 'dist/css/<%= what do I put here? %>.css'
Reconfigure your compileBrandingStyles Target to this instead:
// ...
compileBrandingStyles: {
options: {
strictMath: true,
sourceMap: false,
outputSourceFiles: false
},
files: [{
expand: true,
cwd: 'less/branding/',
src: ['**/*.less'],
dest: 'dist/css/',
ext: '.css'
}]
}
See further info on this in the grunt docs.
EDIT
If you don't' want the sub folders included in the destination folder use flatten.
// ...
compileBrandingStyles: {
options: {
strictMath: true,
sourceMap: false,
outputSourceFiles: false
},
files: [{
expand: true,
cwd: 'less/branding/',
src: ['**/*.less'],
dest: 'dist/css/',
ext: '.css',
flatten: true // <-- Remove all path parts from generated dest paths.
}]
}
My grunt file looks like this:
grunt.initConfig({
compress: {
foo: {
options: { archive: 'deploy/foo.zip', mode: 'zip' },
files: [{ expand: true, cwd: 'release/foo/', src: ['**'], dot: true }]
},
bar: {
options: { archive: 'deploy/bar.zip', mode: 'zip' },
files: [{ expand: true, cwd: 'release/bar/', src: ['**'], dot: true }]
},
baz: {
options: { archive: 'deploy/baz.zip', mode: 'zip' },
files: [{ expand: true, cwd: 'release/baz/', src: ['**'], dot: true }]
},...
How do i parameterise this, so i don't need N definitions and I can call (pseudocode)
> grunt compress "foo"
If I understand your problem correctly:
var initData = {
compress: { }
};
var compress = function(n){
initData.compress[n] = {
options: {archive: 'deploy/' + n + '.zip', mode: 'zip'},
files: [{expand: true, cwd: 'release/' + n + '/', src: ['**'], dot: true}]
};
}
compress('foo');
compress('bar');
compress('baz');
grunt.initConfig(initData);
I want to have a gruntfile with 2 tasks: less (compiles all less files) and watch (listens to changes and re-compiles the changed file).
I have the following Gruntfile.js:
module.exports = function(grunt) {
var files = [
{
expand: true,
cwd: 'media/less',
src: ['*.less'],
dest: 'media/css/',
ext: '.css'
},
{
expand: true,
cwd: 'media/less/vendor',
src: ['*.less'],
dest: 'media/css/vendor/',
ext: '.css'
},
{
expand: true,
cwd: 'media/admin/less',
src: ['*.less'],
dest: 'media/admin/css/',
ext: '.css'
}
];
grunt.initConfig({
less: {
development: {
options: {
compress: false,
yuicompress: true,
optimization: 2
},
files: files
},
production: {
options: {
compress: true,
yuicompress: true,
optimization: 2
},
files: files
}
},
watch: {
styles: {
files: ['media/**/*.less'],
tasks: ['less:development'],
options: {
nospawn: true
}
}
}
});
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.registerTask('default', ['less:development']);
};
The less task runs correctly without any problems. The watch task however listens to changes, but re-compiles all files when one is changed. I suspect it's something to do with how I set up my less task, because I want my less file list to be dynamic and not to add each file manually.
As per this answer grunt should already support this, but I'm unsure how.
Ended up using the watch event and overriding the files property of the less task. Here's my final code:
module.exports = function(grunt) {
var files = [
{
expand: true,
cwd: 'media/less',
src: ['*.less'],
dest: 'media/css/',
ext: '.css',
extDot: 'last'
},
{
expand: true,
cwd: 'media/less/vendor',
src: ['*.less'],
dest: 'media/css/vendor/',
ext: '.css',
extDot: 'last'
},
{
expand: true,
cwd: 'media/admin/less',
src: ['*.less'],
dest: 'media/admin/css/',
ext: '.css',
extDot: 'last'
}
];
grunt.initConfig({
less: {
development: {
options: {
compress: false,
yuicompress: true,
optimization: 2
},
files: files
},
production: {
options: {
compress: true,
yuicompress: true,
optimization: 2
},
files: files
}
},
watch: {
styles: {
files: ['media/**/*.less'],
tasks: ['less:development'],
options: {
nospawn: true
}
}
}
});
grunt.event.on('watch', function(action, filepath){
// ignore include files, TODO: have naming convention
// if an include file has been changed, all files will be re-compiled
if(filepath.indexOf('.inc.') > -1)
return true;
// might not be the most efficient way to do this
var srcDir = filepath.split('/');
var filename = srcDir[srcDir.length - 1];
delete srcDir[srcDir.length - 1];
srcDir = srcDir.join('/');
var destDir = srcDir.replace(/less/g, 'css');
grunt.config('less.development.files', [{
src: filename,
dest: destDir,
expand: true,
cwd: srcDir,
ext: '.css',
extDot: 'last'
}]);
});
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.registerTask('default', ['less:development']);
};
I'm unsure what you mean with the current title of your question Grunt watch less on changed file only. Do you mean that is a problem? That's the expected behavior of a watch task, it will watch the files specified for changes and run the tasks you specified - in this case the LESS compilation.
I did some changes to your file. Some of it was simplified, some was changed keeping flexibility and expandability of the script in mind.
First install underscore as a dependency, by running:
npm install underscore --save-dev
Then do the following changes to your Gruntfile.js:
module.exports = function(grunt) {
var _ = require('underscore');
var files = {
app : {
'<%= path.styles.css %>/styles.css' : '<%= path.styles.less %>/*.less'
},
vendor : {
'<%= path.styles.css %>/styles-vendor.css' : '<%= path.styles.vendor %>/*.less'
},
admin : {
'<%= path.styles.css %>/styles-admin.css' : '<%= path.styles.admin %>/*.less'
}
}
function all() {
'use strict';
var allfiles = {},
i = {};
for (i in files) {
_.extend(allfiles, files[i]);
}
return allfiles;
}
grunt.initConfig({
path : {
media : 'media',
styles : {
css: 'media/css',
less: 'media/less',
admin: 'media/admin/less',
vendor: '<%= path.styles.less %>/vendor'
}
},
less: {
development: {
options: {
compress: false,
yuicompress: true,
optimization: 2
},
files: (all())
},
production: {
options: {
compress: true,
yuicompress: true,
optimization: 2
},
files: (all())
}
},
watch: {
styles: {
files: ['<%= path.media %>/**/*.less'],
tasks: ['less:development'],
options: {
nospawn: true
}
}
}
});
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-contrib-watch');
// run several tasks as default (handy for complex projects)
grunt.registerTask('dist', [ // run with 'grunt dist'
'less:production'
]);
grunt.registerTask('dev', [ // default, will run with 'grunt' only
'less:development'
]);
grunt.registerTask('default', 'dev');
};
If what you want is to actually compile the sets of files separately (files.app, files.vendor & files.admin), you might need to split the task some more, like so:
less: {
app: {
options: {
compress: false,
yuicompress: true,
optimization: 2
},
files: files.app
},
vendor: {
options: {
compress: true,
yuicompress: true,
optimization: 2
},
files: files.vendor
},
admin: {
options: {
compress: true,
yuicompress: true,
optimization: 2
},
files: files.admin
},
development: {
options: {
compress: false,
yuicompress: true,
optimization: 2
},
files: (all())
},
production: {
options: {
compress: true,
yuicompress: true,
optimization: 2
},
files: (all())
}
},
watch: {
all: {
files: ['<%= path.media %>/**/*.less'],
tasks: ['less:development'],
options: {
nospawn: true
}
},
app : {
files: ['<%= path.styles.less %>/*.less'],
tasks: ['less:app'],
options: {
nospawn: true
}
},
vendor : {
files: ['<%= path.styles.vendor %>/*.less'],
tasks: ['less:vendor'],
options: {
nospawn: true
}
},
admin : {
files: ['<%= path.styles.admin %>/*.less'],
tasks: ['less:admin'],
options: {
nospawn: true
}
}
}
Then you could then run either of these:
grunt watch:app
grunt watch:vendor
grunt watch:admin
You can always to choose to run the tasks directly, once:
grunt less:app
grunt less:vendor
grunt less:admin
Hope this helps! Please note that I haven't tested this.
I would like to copy specific coffeescript file (which is not included in the <!-- build:js({.tmp, app}) --> section in my index.html) to for example dist/scripts directory.
I tried with (Gruntfile.js):
copy: {
dist: {
files: [
// ...
{
expand: true,
cwd: './tmp/scripts/polyfill',
dest: '<%= yeoman.dist %>/scripts/polyfill',
src: [
'*'
]
}]
}
},
If you just have one single file you want to copy over, you can use the simpler grunt syntax:
copy: {
dist: {
files: [{
'.tmp/scripts/polyfill/myfile.js': '<%= yeoman.dist %>/scripts/polyfill/myfile.js'
}]
}
}
Also the name of the temporary folder is .tmp, not just tmp.
This worked:
{
expand: true,
cwd: '.tmp/scripts/polyfill',
dest: '<%= yeoman.dist %>/scripts/polyfill',
src: [
'polyfill.js'
]
}
My approach was good, however it contained a typo: ./tmp - it should be .tmp.