Grunt Sass - Compile all Sass files into CSS with the same name - node.js

I used Compass and it compiles all Sass files into CSS with the same name. For example my-style.scss will become my-style.css.
All tutorials about grunt-sass that I found mapped the file name one by one, manually like:
sass: {
dist: {
options: { style: 'compressed' },
files: { 'css/my-style.css': 'sass/my-style.scss' }
}
}
Is there a way to make it more flexible? So I don't need to change the Gruntfile whenever I have new Sass file.
Thanks

Try this format for specifying your source and destination files:
sass: {
src: {
files: [{
expand: true,
cwd: 'source/styles/',
src: ['**/*.scss'],
dest: 'destination/styles/',
ext: '.css'
}]
}
}
This reads as "take all files matching *.scss in source/styles/ and its subfolders, process them and put them into destination/styles/, changing extension to .css. See also http://gruntjs.com/configuring-tasks#building-the-files-object-dynamically

You should use the universal notation:
sass: {
dist: {
options: { style: 'compressed' },
files: { 'css/*/**.css': 'sass/my-style.scss' }
}
}
In this case, the Grunt will go for all *.css files inside the css folder (including subfolders) regardless of the file name, and compile to my-style.scss

Related

Exclude already up-to-date files

I'm using grunt-contrib-imagemin to optimize my images on a project. However, the optimization takes a long time due to the amount of images I'm optimizing.
Therefore, I only want to optimize images which are not existing in the destination OR where the source file is newer then the destination file.
Here is my configuration:
imagemin: {
dist: {
files: [{
expand: true,
cwd: 'src',
src: ['**/*.{jpg,jpeg,png,gif}'],
dest: 'dist/',
filter: 'isFile'
}]
}
}
Is there any way to extend the expansion of files to exclude already existing or newer destination files from the preprocessing?
Use grunt-newer https://github.com/tschaub/grunt-newer
watch: {
imagemin: {
files: ['**/*.{jpg,jpeg,png,gif}'],
tasks: ['newer:imagemin']
}
}

In GruntJS: naming target file with the same name as the source file

In GruntJS, is there any way to name a file generated by a task with the same name as the source file.
For example, if you wanted to compile all .less files to individual .css files, is there any way to do it like this:
files: {
"css/<%= target-filename %>.css": ["less/*.less"]
}
where <%= target-filename %> is the value of * of that current .less file?
If you use the files-array format. you can specify an output extension. see this documentation
something like this should do the trick
files: [
{
expand: true, // Enable dynamic expansion.
src: ['less/*.less'], // Actual pattern(s) to match.
dest: 'css/', // Destination path prefix.
ext: '.css', // Dest filepaths will have this extension.
}
]
Your answer lies in the documentation for building the files object dynamically.
You need to update your code to use expand: true as well as using src, dest and cwd.
Example in the files array format assuming the use of grunt-contrib-less plugin:
files: [{
expand: true, // The magic switch for processing files 1:1
cwd: '<%= target-less-dir %>/',
src: ['*.less'],
dest: '<%= target-css-dir %>'
}]

Grunt watch: compile only one file not all

I have grunt setup to compile all of my coffee files into javascript and maintain all folder structures using dynamic_mappings which works great.
coffee: {
dynamic_mappings: {
files: [{
expand: true,
cwd: 'assets/scripts/src/',
src: '**/*.coffee',
dest: 'assets/scripts/dest/',
ext: '.js'
}]
}
}
What I would like to do is then use watch to compile any changed coffee file and still maintain folder structure. This works using the above task with this watch task:
watch: {
coffeescript: {
files: 'assets/scripts/src/**/*.coffee',
tasks: ['coffee:dynamic_mappings']
}
}
The problem is that when one file changes it compiles the entire directory of coffee into Javascript again, it would be great if it would only compile the single coffee file that was changed into Javascript. Is this naturally possible in Grunt or is this a custom feature. The key here is it must maintain the folder structure otherwise it would be easy.
We have custom watch scripts at work and I'm trying to sell them on Grunt but will need this feature to do it.
You can use something like the following Gruntfile. Whenever a CoffeeScript file changes, it updates the configuration for coffee:dynamic_mappings to only use the modified file as the src.
This example is a slightly modified version of the example in the grunt-contrib-watch readme.
Hope it helps!
var path = require("path");
var srcDir = 'assets/scripts/src/';
var destDir = 'assets/scripts/dest/';
module.exports = function( grunt ) {
grunt.initConfig( {
coffee: {
dynamic_mappings: {
files: [{
expand: true,
cwd: srcDir,
src: '**/*.coffee',
dest: destDir,
ext: '.js'
}]
}
},
watch : {
coffeescript : {
files: 'assets/scripts/src/**/*.coffee',
tasks: "coffee:dynamic_mappings",
options: {
spawn: false, //important so that the task runs in the same context
}
}
}
} );
grunt.event.on('watch', function(action, filepath, target) {
var coffeeConfig = grunt.config( "coffee" );
// Update the files.src to be the path to the modified file (relative to srcDir).
coffeeConfig.dynamic_mappings.files[0].src = path.relative(srcDir, filepath);
grunt.config("coffee", coffeeConfig);
} );
grunt.loadNpmTasks("grunt-contrib-coffee");
grunt.loadNpmTasks("grunt-contrib-watch");
grunt.registerTask("default", [ "coffee:dynamic_mappings", "watch:coffeescript"]);
};
found a solution from an answer to a similar question https://stackoverflow.com/a/19722900/1351350
short answer: try https://github.com/tschaub/grunt-newer

Grunt a TypeScript to JavaScript with uglify

I have 4 TypeScript files under the ts directory. I can compile them all into one file (main.js) with a source map (main.js.map) using the typescript:base task.
However, trying to uglify those files is not working when compiling more than one TypeScript file. It's as if uglify is getting confused when the sourceMapIn was made with more than one file.
How would you compile a TypeScript project with more than one file, into one file with a sourcemap (Back to the original ts files)
Here's the grunt file:
module.exports = function (grunt) {
grunt.initConfig({
uglify: {
dist: {
options: {
sourceMap: '../js/main.min.map',
sourceMapIn: 'main.js.map',
sourceMapRoot: '../ts/'
},
files: {
'../js/main.min.js': ['main.js']
}
}
},
typescript: {
base: {
src: ['**/*.ts'],
dest: '../js/main.js',
options: {
module: 'amd',
sourcemap: true,
declaration: false
}
}
}
});
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-typescript');
grunt.file.setBase('../ts');
grunt.registerTask('default', ['typescript:base', 'uglify:dist']);
};
Thanks!
I tried to reproduce your problem with the following environment:
grunt: 0.4.1
grunt-contrib-uglify: 0.2.2
grunt-typescript: 0.2.4
nodejs: 0.10.15
I had to change uglify.dist.options.sourceMapIn to '../js/main.js.map' and uglify.dist.files['../js/main.min.js'] to ['../js/main.js'], i. e. make the paths relative to the gruntfile location. Afterwards, compilation worked flawlessly and both ../js/main.min.js and ../js/main.min.map looked correct.

Compile less files with grunt-contrib-less won't work

I'm using Grunt for building my web project. I installed grunt-contrib-less package und added a task to my grunt.initConfig({..});
less : {
options: {
paths: ['js/base']
},
files: {
'js/base/*.css' : 'js/base/*.less'
}
}
when I run the target less via grunt less, it runs without errors but doesn't compile the less file to a css file.
Running "less:files" (less) task
Done, without errors.
I have installed the lessc package via node, too. Doing lessc <source> <dest> works fine.
Currently I have pointed with the files option directly to one dir which contains one less file for testing. Even if I write the whole file name into files option, it happens nothing...
Later on I want to scan the whole js directory and compile all new modified *.less files.
I have installed following versions:
grunt-cli v0.1.6
grunt v0.4.0
node v0.8.7
npm 1.1.49
BR,
mybecks
The glob pattern js/base/*.css does not match any files, therefore there is no destination. Usually, tasks like this expect multiple inputs to combine into a single output. Also, bear in mind that less is a multi-task, and putting files as a child of less is not doing what you expect. (it is treating it as a target, not a src/dest map)
If you want a 1-1 transform of .less into .css, you can use dynamic expansion. (or you can define each src/dest pair manually, but who wants to do that?)
In your case:
less: {
options: {
paths: ['js/base']
},
// target name
src: {
// no need for files, the config below should work
expand: true,
cwd: "js/base",
src: "*.less",
ext: ".css"
}
}
I used Anthonies solution but stil had an error
Warning: Object true has no method indexOf
If I changed the order putting expand true as second it gave me the error
Unable to read "less" file
where "less" was the value of the first item in my list.
I solved it by changing files into an array like this:
less: {
options: {
paths: ["js/base"]
},
files: [{
expand: true,
cwd: "js/base",
src: ["**/*.less"],
dest: "js/base",
ext: ".css"
}]
},
I used "grunt-contrib-less" : "^0.11.0"
This works for me, but modified to reflect this scenario:
less: {
options: {
paths: ["js/base"]
},
files: {
expand: true,
cwd: "js/base",
src: ["**/*.less"],
dest: "js/base",
ext: ".css"
}
},

Resources