how to pass file as argument to gulp task - gruntjs

I need some help regarding my gulp task.
I have gulp karma task and I want to pass karma config file as a argument to that task.
I am able to achieve this grunt. Like in grunt , we can use
grunt.option("file")
and we can called grunt task as
grunt taskName --file=myFileName
So How Can I achieve same with gulp?

There's nothing in gulp to parse command line arguments for you.
You can use node's global process.argv directly if you feel like it.
I like to use the yargs module to handle arguments in my gulpfiles.
var args = require('yargs').argv;
var karmaFile = argv.file; // for the argument --file="myFileName"

Adding to #kombucha's answer, here's an example of how to use process.argv. If in your case you passed:
gulp taskName --file myFileName
(without the '=' ) then the below would retrieve the file value:
var filename, i = process.argv.indexOf("--file");
if(i>-1) {
filename = process.argv[i+1];
}
It should be simple enough to turn the above into a generic function for retrieving command-line values. I have used this before to good effect:
function getCLValue(name) {
var i = process.argv.indexOf(name);
return (i>-1) ? process.argv[i+1] : null;
}

Related

Grunt relative file path globbing

Is it possible to use Globbing partially on a directory in a file path?
I have a grunt-contrib-less task set up, the file path for my task looks something like this:
files: {
"../../application/user/themes/some-theme-5.1.1.5830/css/main.css": "less/base.less",
}
However the version number in the relative path may sometime change, such as:
files: {
"../../application/user/themes/some-theme-5.1.1.5831/css/main.css": "less/base.less",
}
Ideally I'd like to something like this:
files: {
"../../application/user/themes/some-theme-*/css/main.css": "less/base.less",
}
Is there a way of doing this? With the above syntax it stops searching after the asterisk.
One potential solution to achieve this is to utilize grunts --options feature.
When running a grunt task via the command line it is possible to specify an additional options value.
In your scenario you could pass in the version number of the folder name that is going to change. (I.e. In your case the part that you tried to specify using the asterisk character (*) E.g. '5.1.1.5830'
Caveat: For this solution to be of any use it does require knowing what that value, (the version number), of the destination folder is upfront prior to running the task via the command line.
Example Gruntfile.js
module.exports = function(grunt) {
grunt.initConfig({
themesFolder: {
namePart: '0.0.0.0' // <-- If no option is passed via the CLI this name will be used.
},
less: {
production: {
options: {
// ...
},
files: {
// The destination path below utilizes a grunt template for the part
// of the folder name that will change. E.g. '5.1.1.0'
'../../application/user/themes/some-theme-<%= themesFolder.name %>/css/main.css': 'less/base.less'
}
}
}
});
grunt.loadNpmTasks('grunt-contrib-less');
grunt.registerTask('saveFolderNameFromOption', 'Uses the option provided to configure name part.', function(n) {
var themesFolder = grunt.option('themesFolder');
if (themesFolder) {
// Store the option value so it can be referenced in the less task.
grunt.config('themesFolder.namePart', themesFolder);
}
});
grunt.registerTask('processLess', ['saveFolderNameFromOption', 'less:production']);
};
Running the ProcessLess task
Run the task via the command line as follows:
$ grunt processLess --themesFolder=5.1.1.5830
Note: The additional option that is specified. Namely: --themesFolder=5.1.1.5830
When using the above command the .css output will be directed to the following path:
'../../application/user/themes/some-theme-5.1.1.5830/css/main.css': 'less/base.less'
Now, each time you run the task you modify the options accordingly.
Benefits: By providing the version number as an option via the CLI will avoid having to reconfigure your Gruntfile.js each time it is run.

How to pass options to handlebars.precompile?

So I've got this code that is running fine (I'm using gulp not grunt for what it matters) :
var handlebars = require('handlebars'),
rename = require('gulp-rename'),
map = require('vinyl-map');
gulp.task('test', function(){
return gulp.src(config.path.template+"/*.handlebars")
.pipe(map(function(contents) {
return handlebars.precompile(contents.toString());
}))
.pipe(rename({ extname: '.js' }))
.pipe(gulp.dest(config.path.template+"/test"))
});
Everything runs perfectly, the .js files generate in the good folder, but I need them to generate without the -s parameter. For an example, when I run handlebars path/to/my/hbs.handlebars -f path/to/my/out/folder.js -s (or --simple), the file generated is the same. But I need this command to run without the -s parameter, and I can't find a way to pass this argument in my gulpfile. I tried alot of things, in a String, in a Json, in an array, tried to go with -s false, with simple false, with isSimple false (something I found in handlebars code).
None of this is working and I really need to pass the -s parameter to false. I assume that I need to do something like :
[...]
return handlebars.precompile(contents.toString(), options);
[...]
But I can't find the proper syntax or way to use these options. And that is my problem.
PS : I use this instead of gulp-handlebars so that I can use the version of handlebars I want to use and not another.
EDIT
Searching in handlebars.js code, I just found that options is an object, but I can't find what he's filled with as I'm not a good javascript user.
It seems to me there's no such switch in the source.
Taken from the precompiler source used from the command line tool:
if (opts.simple) {
output.push(Handlebars.precompile(data, options) + '\n');
} else if (opts.partial) {
if (opts.amd && (opts.templates.length == 1 && !fs.statSync(opts.templates[0]).isDirectory())) {
output.push('return ');
}
output.push('Handlebars.partials[\'' + template + '\'] = template(' + Handlebars.precompile(data, options) + ');\n');
} else {
if (opts.amd && (opts.templates.length == 1 && !fs.statSync(opts.templates[0]).isDirectory())) {
output.push('return ');
}
output.push('templates[\'' + template + '\'] = template(' + Handlebars.precompile(data, options) + ');\n');
}
opts is what you passed in, another variable options is passed to precompile. The decoration is added by the command line tool.
There's a second block with closing brackets a few lines below in the script.
You best copy that source to your code or maybe access the .cli object in your gulp script.

How can I skip a grunt task if a directory is empty

I'm using grunt-contrib's concat and uglify modules to process some javascript. Currently if src/js/ is empty, they will still create an (empty) concat'd file, along with the minified version and a source map.
I want to task to detect if the src/js/ folder is empty before proceeding, and if it is, then the task should skip (not fail). Any ideas how to do this?
The solution may not be the prettiest, but could give you an idea. You'll need to run something like npm install --save-dev glob first. This is based on part of the Milkshake project you mentioned.
grunt.registerTask('build_js', function(){
// get first task's `src` config property and see
// if any file matches the glob pattern
if (grunt.config('concat').js.src.some(function(src){
return require('glob').sync(src).length;
})) {
// if so, run the task chain
grunt.task.run([
'trimtrailingspaces:js'
, 'concat:js'
, 'uglify:yomama'
]);
}
});
A gist for comparison: https://gist.github.com/kosmotaur/61bff2bc807b28a9fcfa
With this plugin:
https://www.npmjs.org/package/grunt-file-exists
You can check file existence. (I didn't try, but the source looks like supporting grunt expands. (*, ** ...)
For example like this::
grunt.initConfig({
fileExists: {
scripts: ['a.js', 'b.js']
},
});
grunt.registerTask('conditionaltask', [
'fileExists',
'maintask',
]);
But maybe if the file doesn't exist it will fail with error instead of simple skip.
(I didn't test it.)
If this is a problem you can modify a bit the source of this plugin to run the related task if the file exists:
The config:
grunt.initConfig({
fileExists: {
scripts: ['a.js', 'b.js'],
options: {tasks: ['maintask']}
},
});
grunt.registerTask('conditionaltask', [
'fileExists',
]);
And you should add this:
grunt.task.run(options.tasks);
In this file:
https://github.com/alexeiskachykhin/grunt-file-exists/blob/master/tasks/fileExists.js
after this line:
grunt.log.ok();
Maybe this is just a more up-to-date answer as the others are more than a year old, but you don't need a plugin for this; you can use grunt.file.expand to test if files matching a certain globbing pattern exist.
Update of #Kosmotaur's answer (path is just hard-code here though for simplicity):
grunt.registerTask('build_js', function(){
// if any file matches the glob pattern
if (grunt.file.expand("subdir/**/*.js").length) { /** new bit here **/
// if so, run the task chain
grunt.task.run([
'trimtrailingspaces:js'
, 'concat:js'
, 'uglify:yomama'
]);
}
});

Gruntjs: Loading config files based on target

I'd like to be able to run the same builds for different targets by passing in config information from a build file, e.g. grunt build:target1 and grunt build:target2...
I figured I could access the target within the grunt file
module.exports = function ( grunt ) {
var userConfig = require( **'./'+grunt.task.current.name+'build.config.js'** );
var taskConfig...
grunt.initConfig( grunt.util._.extend( userConfig, taskConfig ) );
But the target is only available within a task.
Is there another way of accomplishing something like this?
You can pass command line arguments to Grunt by passing them using two dashes, like
--[your_arg_name]=[arg_value].
Example:
grunt --target=debug
Then retrieve this value in your Grunt config file by calling
module.exports = function (grunt) {
var target = grunt.option('target'),
userConfig = require('./' + target + "build.config.js");
...
}
You can choose whichever name you like, I chose target in my examples above.

gruntjs - command line arguments

Where can I get a handle for command line arguments?
eg grunt dist --env=UAT. How do I get the value for env?
While I'm at it, how would I assign a default value to this if it's not set on the command line?
You can use grunt.option() or more specifically:
var env = grunt.option('env') || 'default';
to grab the env argument or default to the string 'default' if the argument is not present.
I find the handling of defaults in grunt to be sorely lacking. The method outlined above works, but it quickly gets tiresome when you have lots of options.
A little helper function can ease this:
function defaultOptions(options) {
for(var key in options) {
if(options.hasOwnProperty(key) && !grunt.option(key)) {
grunt.option(key, options[key]);
}
}
}
You can then use like:
defaultOptions({
env : "staging"
});
And at the CLI:
grunt // { env : "staging" }
grunt --env=UAT // { env : "UAT" }

Resources