Expand not working in grunt-contrib-less task for dynamic selection - css

I've been playing with Grunt and one of the things I wanted to use it for was to compile my LESS files, but for some reason the expand: true (I commented everything out from the bottom up and it stopped throwing the err after commenting out expand) in the less:mini task is causing this error: Warning: Object true has no method 'indexOf' Use --force to continue. Does anyone know why this is happening? I can dynamically build the file object in grunt-contrib-copy no problem, and expand is required for the other options to work.
less: { // Set up to detect files dynamically versus statically
mini: {
options: {
cleancss: true, // minify
report: 'min' // minification results
},
files: {
expand: true, // set to true to enable options following options:
cwd: "dev/less/", // all sources relative to this path
src: "*.less", // source folder patterns to match, relative to cwd
dest: "dev/css/", // destination folder path prefix
ext: ".css", // replace any existing extension with this value in dest folder
flatten: true // flatten folder structure to single level
}
}
}
Thanks

files is intended to be used as an array or src-dest mappings. Grunt is interpreting the above properties within less.mini.files as src-dest mappings. See: http://gruntjs.com/configuring-tasks#files-object-format
You don't need to nest properties within files if you're not using that format. Modify your config to:
less: { // Set up to detect files dynamically versus statically
mini: {
options: {
cleancss: true, // minify
report: 'min' // minification results
},
expand: true, // set to true to enable options following options:
cwd: "dev/less/", // all sources relative to this path
src: "*.less", // source folder patterns to match, relative to cwd
dest: "dev/css/", // destination folder path prefix
ext: ".css", // replace any existing extension with this value in dest folder
flatten: true // flatten folder structure to single level
}
}

Related

How do I generate sourcemaps for Uglified files using Grunt?

I have a Grunt project that uses both Browserify and Uglify. Here are the core bits of it:
browserify: {
myapp: {
options: {
transform: ['babelify'],
browserifyOptions: {
debug: true
},
},
src: 'src/index.js',
dest: 'build/myapp.js'
}
},
uglify: {
options: {
sourceMap: true,
banner: bannerContent
},
target: {
src: 'build/myapp.js',
dest: 'build/myapp.min.js'
}
},
It seems to generate a myapp.min.js.map file but it no longer has the raw sources in the source-map that existed prior to the Browserification.
Here's what the resultant source-map file contains:
{
"version":3,
"sources":[
"myapp.js"
],
"names":[
...
...
...
],
"mappings":".........",
"file":"myapp.min.js"
}
I've tried using the uglifyify transform for Browserify but that does not seem to generate as small files as the Uglify task.
I've also bumped all my dependencies to the latest but I haven't been able to resolve this issue.
grunt-contrib-uglify has a sourceMapIn option that allows you to specify the location of an input source map file from an earlier compilation - which in your scenario is the browserify task.
However, whilst setting browserifyOptions: { debug: true } in your browserify task does generate an inline source map in the resultant .js file (i.e. in build/myapp.js), the crux of the problem is twofold:
We don't have an external source map file that we can configure the sourceMapIn option of the subsequent grunt-contrib-uglify task to utilize.
grunt-browserify doesn't provide a feature to create an external .map file, it only creates them inline (see here)
To address the aforementioned issue consider utilizing grunt-extract-sourcemap to extract the inline source map from build/myapp.js (i.e. from the output file generated by your browserify task) after it has been produced.
Gruntfile.js
The following gist shows how your Gruntfile.js should be configured:
module.exports = function (grunt) {
grunt.initConfig({
browserify: {
myapp: {
options: {
transform: ['babelify'],
browserifyOptions: {
debug: true
},
},
src: 'src/index.js',
dest: 'build/myapp.js'
}
},
extract_sourcemap: {
myapp: {
files: {
'build': ['build/myapp.js']
}
}
},
uglify: {
options: {
sourceMap: true,
sourceMapIn: 'build/myapp.js.map'
},
target: {
src: 'build/myapp.js',
dest: 'build/myapp.min.js'
}
}
});
grunt.loadNpmTasks('grunt-browserify');
grunt.loadNpmTasks('grunt-extract-sourcemap');
grunt.loadNpmTasks('grunt-contrib-uglify');
// Note the order of the tasks in your task list is important.
grunt.registerTask('default', ['browserify', 'extract_sourcemap', 'uglify']);
};
Explanation
First the browserify task is invoked which outputs a new file (i.e. build/myapp.js) containing your bundled JavaScript and an "inlined" source map info. If you were to inspect the content of build/myapp.js at this stage it includes something like the following at the end:
//# sourceMappingURL=data:application/json;charset=utf-8;base64, ...
Next the extract_sourcemap task is invoked. This essentially extracts the "inlined" source map info from build/myapp.js and writes it to a new file named myapp.js.map which is saved in your build directory.
The original "inlined" source map info in build/myapp.js is replaced with a link to the newly generated source map file, i.e. myapp.js.map. If you inspect the content of build/myapp.js you'll now notice the following at the end of the file instead:
//# sourceMappingURL=myapp.js.map
Lastly the uglify task is invoked. Notice how its sourceMapIn option is configured to read build/myapp.js.map, i.e the source map file we generated at step 2.
This task creates your desired build/myapp.min.js file containing; your minified JS, and a link to a newly generated source map file build/myapp.min.js.map.
Note The final resultant file (i.e. build/myapp.min.js) now correctly maps back to the original src/index.js file and any file(s) that index.js itself may have import'ed or require()'d

Specifying Grunt output to a dynamic parallel folder

The Context
I'm new to Grunt and am trying to learn a bit by modifying the meanjs boilerplate to support stylus, I would like to keep my precompiled css assets organized in modular buckets, as recommended by the current meanjs defaults.
The Question
I have the following file structure:
- app
- config
- public
- modules
- foo
- assets
- stylesheets
...
- css
...
...
How can I use Grunt to take Stylus .styl files in the public/modules/*/assets/stylesheets directory, and have them compile to the public/modules/*/css directory?
Naive Attempt:
Below is an example attempt, which didn't get very far.
stylus: {
compile: {
files: [{
dest: '../../css',
src: 'public/modules/*/assets/stylesheets/*.styl',
ext: '.css',
expand: true
}]
}
}
This results in: File ../../css/public/modules/foo/assets/stylesheets/baz.css created.
If I leave "dest" empty, it does properly compile but the output is in the assets/stylesheets folder (as expected). I'm sure there is a clean way to do this, but I don't know yet.
setting the src, dest, cwd, as well as using the hidden rename options of grunt should get stylus files in your desired format.
example:
stylus: {
compile: {
options: {
compress: true
},
files: [{
cwd: 'public/modules',
dest: 'public/modules',
src: ['*/assets/stylesheets/*.styl'],
expand: true,
rename: function(dest, src) {
var path = require('path');
var module = src.split(path.sep).slice(0,1)[0];
return path.join(dest, module + '/css/' + module + '.css');
}
}]
}
},
grunt tricks - customize file output rename

How to set CSS Source Map output destination when grunt-contrib-less is used

I am using grunt-contrib-less for compiling less files.
I have grunt locally installed at root of project folder.
The css files are located at qa1/avinash/html5/phase1/css/ path from root of project folder.
So this is the path i am specifying for cwd (current working directory), src and dest parameters of the grunt-less task. there are no issues in compilation of css and source map.
The only issue i face is that the source map is generated in the same folder of gruntfile. but my generated css is at the dest path i specified. since the css and source map are at different locations i have to manually edit the less path references in source map and bring it to the generated css directory. or use sourceMapURL to specify the source map location ../../../../../style.css.map(backwards). Both ways are not convenient.
So can anyone help me how to specify the source map output destination path like we specify for destination path for generated css something like
sourceMapDest: 'qa1/avinash/html5/phase1/css/'
--
currently used Gruntfile.js:
module.exports = function(grunt) {
grunt.initConfig({
less: {
options: {
sourceMap:true,
sourceMapFilename: "style.css.map",
sourceMapURL: '../../../../../style.css.map'
},
src: {
// no need for files, the config below should work
expand: true,
cwd: "qa1/avinash/html5/phase1/css/",
src: "style.less",
dest: "qa1/avinash/html5/phase1/css/",
ext: ".css"
}
},
watch: {
js: {
files: ['qa1/avinash/html5/phase1/css/'],
tasks: ['default'],
}
}
});
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.registerTask('default', ['less']);
};
The sourceMapFilename option may include a path part as well.
I.e. just change it to:
sourceMapFilename: "qa1/avinash/html5/phase1/css/style.css.map"

grunt-contrib-compress exclude dot folder

I'm using the grunt-contrib-compress task to compress the contents of the dist/ folder inside a ZIP archive. To do that I'm using the following configuration:
compress: {
dist: {
options: {
archive: 'dist/<%= pkg.name %>-<%= pkg.version %>.zip'
},
files: [{
cwd: 'dist/',
expand: true,
src: [ '**' ]
}]
}
},
This is working great (all files are zipped), however, it also adds a folder called ".". I suppose that it's there because I'm including **, which also includes the current folder (a single dot).
For example:
Is there a way to prevent this folder to be added to the ZIP?
I tried adding !. to my src but that did not seem to do the trick. I also read about the dot property, but setting it to false did not help either.
You need src: ['**/*'] because ** in minimatch is a "Globstar" matcher, it matches everything including directory itself (the dot-directory). However, pattern **/* means "include all files and subdirectories" but dot-directory neither subdirectory nor file and it does not match it.

Grunt recursive copy

I'm setting up a Grunt script that needs to copy and reorganise directories of images from A to B. Simple enough.
Directory structure:
components
componentA
js
img
imgfolderA
imgfolderB
css
componentB
js
img
imgfolderA
Each img directory could contain other directories and directories within those directories to help organise the images.
I want to use Grunt to take all those images and put them under one directory (assets/img):
assets
img
dirA
imgfolderA
imgfolderB
dirB
imgfolderA
Any ideas on how could I do this in grunt without specifying each component directory (it needs to be fully automated)?
know it's a bit late but this should do the job, use 'grunt-contrib-copy' like so
module.exports = function (grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
copy: {
production: {
files: [{
expand: true,
cwd: "componentA/img/imgfolderA/",
src: ["*.*", "**/*.*"],
dest: "./assets/img/dirA/",
},
{
expand: true,
cwd: "componentB/img/imgfolderB/",
src: ["*.*", "**/*.*"],
dest: "./assets/img/dirB/",
},
]
}
}
});
// Production Build Tools
grunt.loadNpmTasks('grunt-contrib-copy');
// Default Production Build task(s).
grunt.registerTask('default', ['copy']);
};
ps magic is in the files objects, there not very well documented, but the documentation is here, after one or two reads it makes sense honest!
grunt-contrib-copy setup: https://github.com/gruntjs/grunt-contrib-copy (the readme at the bottom)
files object setup: http://gruntjs.com/configuring-tasks#globbing-patterns
task setup: http://gruntjs.com/configuring-tasks
This is rather simple using grunt.file.expand.
Just pass matching glob patterns (e.g. **/img/**), and then recurse on the returned matching file values to copy.

Resources