With Grunt, how can I compile all *.less files, if I have global mixins and constants? - gruntjs

I want to organize my HTML, JS, and LESS by module. I'm already using Grunt to compile *.js and *.html from my source folders.
So I configured grunt as follows:
grunt.initConfig({
less: {
ALL: {
files: { 'compiled.css': '**/*.less' }
}
}
}
But this runs into a major problem: constants and mixins from my /helper/*.less files are not accessible to other .less files.
It seems like grunt-contrib-less compiles each individual .less file, and then combines the output, but doesn't compile anything "globally".
The only solution I can think of is to create and maintain a master.less that #imports each individual .less file. But I'm trying to achieve an extremely modular build process, and I don't have to list any HTML or JS files, so I'm really hoping to find a *.less solution too!

Thanks to #seven-phases-max for the following answer!
less-plugin-glob
Allows you to use wildcards in #import statements! Works perfectly!
// master.less
#import "helpers/**/*.less";
#import "modules/**/*.less";
And all you need to add to your Grunt configuration is the plugins option:
// Gruntfile.js
grunt.initConfig({
less: {
'MASTER': {
src: 'master.less',
dest: 'master.css',
options: {
plugins: [ require('less-plugin-glob') ]
}
}
}
});
And, don't forget, npm install less-plugin-glob.

Here's one way to achieve an effortless development experience.
However, it requires a generated file and a custom task.
Auto-generate the master.less file
Create a task that generates master.less by writing an #import statement for each *.less file:
grunt.registerTask('generate-master-less', '', function() {
generateFileList({
srcCwd: 'modules',
src: '**/*.less',
dest: 'less/master.less',
header: '// THIS FILE IS AUTOMATICALLY GENERATED BY grunt generate-master-less\n',
footer: '// THIS FILE IS AUTOMATICALLY GENERATED BY grunt generate-master-less\n',
template: '#import "<%= filename %>";\n',
join: ''
});
});
function generateFileList(options) {
var _ = grunt.util._;
var files = grunt.file.expand({ cwd: options.srcCwd }, options.src);
var results = files.map(function (filename) {
return _.template(options.template, { 'filename': filename });
});
var result = options.header + results.join(options.join) + options.footer;
grunt.file.write(options.dest, result);
}
Then, use grunt-contrib-less to just build master.less.

Related

Keeping LESS sourceMaps for minified css with cssmin

My LESS files are compiled with grunt-contrib-less and corresponding grunt task with the following config:
module.exports = {
options: {
sourceMap: true,
sourceMapFilename: 'Content/styles/e-life.css.map'
},
compile: {
files: {
'Content/styles/e-life.css' : 'Content/styles/common.less'
}
}
}
Then I procced with cssmin for output css file. I get it minified, but I want to bind source maps from the previous step for the minified css.
module.exports = {
options: {
sourceMap: 'Content/styles/e-life.css.map'
},
all: {
files: {
'Content/styles/e-life.css': ['Content/styles/e-life.css']
}
}
}
The task fails if I mention source map path in options.sourceMap. I see the following in css-clean docs:
sourceMap - exposes source map under sourceMap property, e.g. new CleanCSS().minify(source).sourceMap (default is false) If input styles are a product of CSS preprocessor (Less, Sass) an input source map can be passed as a string.
But i can not understand how to pass this string to the task. Is it even possible? How can I do this?
grunt-contrib-cssmin does NOT let you chain sourcemaps.
Its sourceMap option is true/false only, and will generate a map from the minified css to the original css, not to the original Less, sorry.
Considering that source mapping is useful mainly for debugging, I would suggest:
do not use cssmin in your development environment, that way you get mapping from css to your Less files if needed.
use cssmin without mapping for production.
You could also avoid the Grunt cssmin task and use the Less compression with compress option.
module.exports = {
options: {
compress: true,
sourceMap: true,
sourceMapFilename: 'Content/styles/e-life.css.map'
},
compile: {
files: {
'Content/styles/e-life.css' : 'Content/styles/common.less'
}
}
}
https://github.com/gruntjs/grunt-contrib-less#compress

Grunt + Sass, how do I include subfolder scss when I compile?

I'm trying to change my sass workflow by including it in grunt and compiling from there. I can compile successfully if all my scss files are in one folder:
sass: {
dist: {
options: {
style: 'compact'
},
files: {
'style.css': 'css/*.scss'
}
}
}
however my usual file structure includes a subfolder for components exclusive to certain pages. Grunt is recognising the top level .scss files but nothing below it. I also tried this:
sass: {
dist: {
options: {
style: 'compact'
},
files: {
'style.css': 'css/main.scss',
'style.css': 'css/pages/*.scss'
}
}
}
but no joy there either. How do I compile to a single css file from multiple scss locations?
You must add /**/ after your folder, like so:
'style.css': 'css/**/*.scss'
You can see the documentation here: http://gruntjs.com/configuring-tasks#globbing-patterns

Is it possible with Grunt to merge all js/css files in a specific folder in to one js/css file?

I'm new with Grunt and I wasn't able to find what I'm looking for.
I have this folder's structure configuration :
app/
public/
assets/
... some javascript/css libs like jQuery, Bootstrap, etc
css/
js/
img/
What I'd like to do is compress all the js files in public/assets/ into one assets.js file that would be in js/assets.js, and do the same for all the css files into assets.css in css/assets.css.
Moreover, I'd like those two assets.js/css file to be compressed.
A link to a solution or some start of a solution is all I need.
Thank you!
Firstly you need to concatenate your files and then run them through a minifier. Grunt has plenty of plugins that will do these things but some of the more popular ones are grunt-contrib-concat, grunt-contrib-uglify and grunt-contrib-cssmin.
These tasks have plenty of options available to taylor them to your needs but this should help you get started.
As sample configuration for the concat task would be something like:
grunt.initConfig({
concat: {
options: {
separator: ';',
},
js: {
src: ['public/assets/a.js', 'public/assets/b.js', 'public/assets/c.js'],
dest: 'public/js/assets.js',
},
js: {
src: ['public/assets/a.css', 'public/assets/b.css', 'public/assets/c.css'],
dest: 'public/css/assets.css',
},
},
});
Then for your minify js task:
uglify: {
js: {
files: {
'public/assets/js/assets.min.js': 'public/assets/js/assets.js'
}
}
}
And finally, css minify task:
cssmin: {
files: {
'public/assets/css/assets.min.css' : 'public/assets/css/assets.css'
}
}

Add grunt task to linemanjs application.js

I want to add a grunt task (specifically angular-template) to my lineman application.js file. There is some documentation found here and here. However, it just tells me to add the grunt task to loadNpmTasks. The problem is that from a fresh project created using lineman, my application.js file does not have a loadNpmTasks array, nor do the comments point out where I should put it. Both examples I have found in the documentations do not show what the application.js file should look like in it's entirety.
The application.js file should look something like this (obviously the src/dest options are not configured correctly:
module.exports = function(lineman) {
return {
loadNpmTasks:['grunt-angular-templates'],
ngtemplates: {
app: {
src: '**.html',
dest: 'templates.js'
}
}
};
};
Then to run the task:
lineman grunt ngtemplates

Using output of one task as an input for another

I have an html file that contains references to js files. I want to parse it extract a list of referenced js files and feed contrib-concat or any other task with them.
Is there any convenient way to use output of one grunt task as an input for another?
Use grunt.config. Here is an example:
grunt.initConfig({
concat: {
js: {
src: ['default/concat/files/*'],
dest: ['dist/javascript.js'],
},
},
});
grunt.registerTask('extractjs', function() {
/* Do the js extraction */
// Overwrite the concat.js.src with your extracted files.
grunt.config(['concat', 'js', 'src'], extractedFiles);
});
So now when you run grunt extractjs concat it will extract the js and then concat the extracted js files. Check out this task: https://github.com/cgross/grunt-dom-munger as he is working on a similar goal. Here is a grunt issue with more examples as well: https://github.com/gruntjs/grunt/issues/747

Resources