How do I parse '<%= =>' in grunt? - javascript

A lot of grunt plugins allow for this syntax when telling it to include files:
['<%= src_dir %>/common/**/*.js', '<%= src_dir %>/app/**/*.js']
or
['<%= test_files.js %>']
Is there any way I can call into some library that will parse these and give me an array of the actual output? Or is this built directly into grunt? I am not sure what terms to google to even make this show up.
Thanks

You are either looking for grunt.config.get, grunt.config.process or grunt.template.process, depending on where you are getting the values from and how you want to process them.
grunt.config.get
Get a value from the project's Grunt configuration. If prop is specified, that property's value is returned, or null if that property is not defined. If prop isn't specified, a copy of the entire config object is returned. Templates strings will be recursively processed using the grunt.config.process method.
grunt.config.get([prop])
grunt.config.process
Process a value, recursively expanding <% %> templates (via the grunt.template.process method) in the context of the Grunt config, as they are encountered. this method is called automatically by grunt.config.get but not by grunt.config.getRaw.
grunt.config.process(value)
[...]
grunt.template.process
Process a Lo-Dash template string. The template argument will be processed recursively until there are no more templates to process.
The default data object is the entire config object, but if options.data is set, that object will be used instead. The default template delimiters are <% %> but if options.delimiters is set to a custom delimiter name (set with grunt.template.addDelimiters), those template delimiters will be used instead.
grunt.template.process(template [, options])
Inside templates, the grunt object is exposed so that you can do things like <%= grunt.template.today('yyyy') %>. Note that if the data object already has a grunt property, the grunt API will not be accessible in templates.
In this example, the baz property is processed recursively until there are no more <% %> templates to process.
var obj = {
foo: 'c',
bar: 'b<%= foo %>d',
baz: 'a<%= bar %>e'
};
grunt.template.process('<%= baz %>', {data: obj}) // 'abcde'

Related

custom grunt task naming convention

Is there any convention regarding naming custom grunt tasks that include more than one word? For example: grunt-json-schema grunt plugin has json_schema task. One name includes dashes (-), the other includes underscores (_).
Obviously, dashed-name can't be used as a JavaScript object key:
grunt.initConfig({
json-schema: { // WON'T work
they have to be enclosed in quotes:
grunt.initConfig({
'json-schema': { // will work
I checked all official plugins (grunt-contrib-*), but they all consist of only one word. The motivation foor this question is simple: I just want to follow conventions.
Short answer: Plugin/custom task names do not have to correlate to a specific config object name.
The Grunt.js api allows access to the config object using the method grunt.config. Tasks & Plugins have access to the entire object, not just the sub object correlating to the name.
For example, I could create a task called foo that accesses the config from bar:
grunt.initConfig({
bar: {
baz: true
}
});
grunt.registerTask('foo', 'example custom task', function () {
var config = grunt.config('bar');
grunt.log.ok(config);
});
Best practice: Plugin developers should name the key for their config object similar to the plugin name itself. This helps mitigate conflicts with other plugins who could reference similar.
grunt.initConfig({
foo: {
baz: true
}
});
grunt.registerTask('foo', 'example custom task', function () {
var config = grunt.config('foo');
grunt.log.ok(config);
});
I think the general convention is to use camelCase for tasks that consist of multiple words.

How to overwrite grunt task options in grunt-cli?

I am using grunt-contrib-concat and I have a simple concat task / config like below
concat: {
options: {
sourceMap: true
},
vendor: {
src:['lib/**/*.js'],
dest: 'dist/scripts/vendor.js'
},
app: {
src:['app/**/*.js'],
dest: 'dist/scripts/app.js'
}
}
So when I am running above task through console I would like to be able to specify enable / disable sourceMap generation. Source map generation can take forever.
I tried below but none worked.
grunt concat:vendor --sourceMap=false
grunt concat --sourceMap=false
Thanks.
I know one way to do this, it requires you to write a custom task, it's easy.
// Leave your `concat` task as above
concat: ...
// and then define a custom task as below (out of `grunt.config.init` call)
grunt.registerTask('TASK_NAME', 'OPTIONAL_DESCRIPTION', function (arg) {
// CLI can pass an argument which will be passed in this function as `arg` parameter
// We use this parameter to alter the `sourceMap` option
if (arg) {
grunt.config.set('concat.options.sourceMap', false);
}
// Just run `concat` with modified options or pass in an array as tasks list
grunt.task.run('concat');
});
This is simple, you can customize this template as your wishes.
To use it, just use a ":" to pass extra parameter(s) in CLI like below:
$ grunt concat:noSrcMap
Basically you can pass anything as the parameter, it will be treated like a string (or undefined if no parameter passed).

r.js optimizer - don't mangle function names

I am using r.js with uglify to minify and concatenate my scripts. I am getting some errors on a production site where the stack trace returned is unintelligible. I would like to temporarily turn off the mangling of function names (variable names are fine) and am having trouble working out how to do this as r.js wraps the configuration options that are passed to uglify.js
The uglify config section in my r,js build config looks like this
uglify: {
beautify: true,
indent_start: 0,
indent_level: 1,
}
I would like to add the
-nmf or --no-mangle-functions – in case you want to mangle variable names, but not touch function names. (from here)
If i add the line
uglify: {
beautify: true,
indent_start: 0,
indent_level: 1,
'--no-mangle-functions': true
}
It does nothing, as does 'no-mangle-functions': true.
How do I pass this option to uglify?
Trying to make uglified/mangled code readable kind of defeats it's purpose in the first place.
Probably, what you are after are source maps.
To generate source maps in Uglify just add these options:
uglify: {
options: {
sourceMap: 'build.min.map',
sourceMappingURL: 'build.min.map'
}
}
Map filename must mirror the final javascript filename:
uglified.js <=> uglified.map
From what i can see in the source code of r.js there is no direct differentiation between functions and variable names. But there is an option called no_functions which is actually passed to the uglify section where the default value is false
Passing of options:
https://github.com/jrburke/r.js/blob/master/dist/r.js#L25067
Defaulting no_functionsto false:
https://github.com/jrburke/r.js/blob/master/dist/r.js#L11492
I cannot test it right now, so i am only guessing. Maybe you can try this option

How to use YAML front matter in the destination directory path?

I want the path of my blog posts to use the fancy date format e.g. /blog/2013/09/17 so the links from my old octopress blog are not broken.
In the YAML front matter on each markdown page I have added the date.
---
date: 2013-09-13
---
So in the Gruntfile.js I want to do something like this:
dest: './blog/<%= date.getFullYear() %>/<%= date.getMonth() %>/<%= date.getDate() %>'
Though can't find a way to get hold of that date property from the YFM. Is this possible, and it is the right way to achieve what I want?
EDIT: Since this answer was initially posted, a permalinks plugin was published that makes this super easy: https://github.com/assemble/assemble-contrib-permalinks
I think a better approach would be to create a feature request at http://github.com/assemble/assemble/issues, however, if you prefer to find a way to use custom logic in lodash templates inside the gruntfile, then my suggestion would be to create mixins that can then be used in your templates.
To add mixins, just do something like this outside the initConfig object (there are other ways, but this is easiest):
module.exports = function (grunt) {
grunt.util._.mixin({
year: function(foo) {
return date.getFullYear(foo);
},
month: function(foo) {
return date.getMonth(foo);
},
day: function(foo) {
return date.getDay(foo);
}
});
grunt.initConfig({
foo: {
src: 'path/to/my/files/**`
// Now we can use the mixins like this:
dest: <%= _.year() %>/<%= _.month() %>/<%= _.day() %>'
});
grunt.registerTask(...);
};
The challenge with this approach is getting the context from the YAML front matter of the src files and then returning the dates to be used in the dest paths. Alternatively, this should't be difficult to implement as a native feature in assemble, and I think others would benefit from it as well.

Generate dynamic filenames with grunt.js

Is it possible to generate dynamic filenames outside the built-in grunt tasks (e.g. concat or min)? I tried to use something like <config:concat.dist.dest> or <%= dirs.dest %> as it is described in the docs. But this never gets interpreted / compiled, it just writes out the string.
Update:
That's what I tried based on jakub.g's answer. My grunt.js looks like this:
// ... grunt file contents
jquery: {
exclude: [],
version: '1.8.3',
dest: '../dist/js/jquery-' + grunt.task.directive('<config:jquery.version>') + '.js',
minify: false
}, // ... even more grunt file contents
grunt.task.directive('<config:jquery.version>') returns null. So the filename was named jquery-null.js.
I then tried grunt.template.process('<%= grunt.jquery.version %>') and grunt.config.process('<%= grunt.jquery.version %>'), but none of them worked.
This is hidden under the hood of Grunt magic in the built-in tasks and in fact not documented clear enough.
You need to use sth like grunt.task.directive(dest) to evaluate things like <config:..>. in a custom task.
For <%= foo %>, have a look at Grunt templates.
Furthermore, wildcards like * and ** and also not expanded by default, if you want to use them in custom tasks, you may use grunt.file.expandFiles().

Categories