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

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"

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

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

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
}
}

Using Grunt Copy to copy images to new directory

I'm using Grunt 0.4.1 and Grunt-contrib-copy version 0.4.1. I'm trying to copy images from a src directory to a distribution directory, but it's copying the full src directory instead of only the contents of the images directory. In other words, this is creating dist/images/src/images/..., whereas I want the result to just be dist/images/...
Here's my copy task:
copy: {
images: {
files: {
'dist/images/': 'src/images/**/*'
}
}
}
And it's being run as follows:
// Default task.
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.registerTask('default', ['less', 'concat', 'uglify', 'cssmin', 'copy']);
How do I get it so that only the subdirectories of src/images get copied into dist/images?
These files are already compressed and only need to be copied to the destination during build.
What actually fixed my problem was designating the root directory structure from which I was copying with the "cwd" directive and then the src exactly like above. Just came back to post this and saw the same solution basically that I had come up with. Here is what worked for me:
copy: {
images: {
files: [
{
expand: true,
cwd: 'src/images/',
src: ['**/*.{png,jpg,svg}'],
dest:'dist/images/'
}
]
}
}
The "cwd" property allows you to define the root of the source from which you are copying. This will not be included in the path of the copied files. So in my case, by defined "cwd" as "src/images", I'm then able to define the source as "**/*.{png,jpg,svg}" This finds all the subdirectories in the source images directory and only copies the files with the extensions I've provided. This gives me the result I want: dist/images/... with all the subdirectories as expected.
Without using "cwd", the grunt-contrib-copy literally copies the entire source tree structure into the destination. The "cwd" property allows you to cherry pick subdirectories and files from one file structure and copy them into another.
You'll want to specify the flatten option, which removes the directory tree.
copy: {
images: {
expand: true,
cwd: 'src/images/',
src: ['**/*'],
dest: 'dist/images/',
filter: 'isFile',
flatten: true
}
}

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