Update variable used by Grunt Template - gruntjs

I am using Grunt Templates, but wondering how I can update the variable which is used. Please check out the example below.
(function () {
"use strict";
module.exports = function(grunt) {
grunt.initConfig({
directory: 'deploy', // I want to be able to update this
concat: {
options: {
separator: ';\n\n',
banner: '/*! Last edited: <%= grunt.template.today("yyyy-mm-dd") %> */\n /* DO NOT EDIT THIS FILE DIRECTLY */\n\n'
},
js_site: {
src: '<%= directory %>/assets/js/src/*.js',
dest: '<%= directory %>/assets/js/site.js',
},
js_vendor: {
src: '<%= directory %>/assets/js/vendor/*.js',
dest: '<%= directory %>/assets/js/vendor.js',
}
},
});
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.registerTask('watch', function() {
var args = process.argv;
var dir = args[args.indexOf('--dir') + 1];
// Now update the directory variable above
});
};
})();

This should work :
(function () {
"use strict";
module.exports = function(grunt) {
grunt.initConfig({
directory: 'deploy', // I want to be able to update this
concat: {
options: {
separator: ';\n\n',
banner: '/*! Last edited: <%= grunt.template.today("yyyy-mm-dd") %> */\n /* DO NOT EDIT THIS FILE DIRECTLY */\n\n'
},
js_site: {
src: '<%= directory %>/assets/js/src/*.js',
dest: '<%= directory %>/assets/js/site.js',
},
js_vendor: {
src: '<%= directory %>/assets/js/vendor/*.js',
dest: '<%= directory %>/assets/js/vendor.js',
}
},
});
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.registerTask('watch', function() {
var args = process.argv;
var dir = args[args.indexOf('--dir') + 1];
// Now update the directory variable above
grunt.config.set('directory', dir);
});
};
})();

Related

How do I include the filename in an uglify banner in grunt?

I am using grunt to minify some JS files. It would be nice to include the filename in the banner. I have found several examples how to include the package name in the banner, but I haven't yet managed to get the filename in there. So: What do I have to put in the gruntfile (see below) instead of pkg.name to get the source filename (or the dest filename) in there?
Thanks in advance
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
uglify: {
options: {
banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
},
build: {
files: [{
expand: true,
src: '**/*.js',
dest: 'build',
cwd: 'src',
ext: '.min.js'
}]
}
}
});
// Load the plugin that provides the "uglify" task.
grunt.loadNpmTasks('grunt-contrib-uglify');
// Default task(s).
grunt.registerTask('default', ['uglify']);
};
I tried to do the same thing, and couldn't find any reference to the current filename that was exposed to the template. Here's the workaround I finally figured out; it's a custom task that dynamically creates a new target for each file:
grunt.registerMultiTask('minify', function () {
this.files.forEach(function (file) {
var path = file.src[0],
target = path.match(/src\/(.*)\.js/)[1];
// store some information about this file in config
grunt.config('ugtargets.' + target, {
path: path,
filename: path.split('/').pop()
});
// create and run an uglify target for this file
grunt.config('uglify.' + target + '.files', [{
src: [path],
dest: path.replace(/^src\/(.*)\.js$/, 'build/$1.min.js')
}]);
grunt.task.run('uglify:' + target);
});
});
And my uglify config:
uglify: {
options: {
banner: 'Filename: <% ugtargets[grunt.task.current.target].filename %>\n'
}
}
For each file in your source directory, we create a target name out of the filename. The exact process will depend on how your files are named; you'll want to strip out any dots or slashes. Here I used a regex; in my app I actually used fs to read some JSDoc data from the files themselves.
Then we store that filename in an object in the Grunt configuration, indexed by the target name. Here I used an object with a couple of properties; you could add more stuff here or just use a plain string if you wanted.
Finally we add a target configuration to the uglify config. This is just the src and dest for the current file; we have to do our own filename processing but it's not much work. Then we run the uglify task with the new target.
In the banner template, you can now use grunt.task.current.target to grab the data we stored in the config earlier. Presto!
In case you have more scripts to be uglify is convenient to separate it to particular subtasks with custom property as name identifier.
uglify: {
options: {
banner:
'<% var subtask = uglify[grunt.task.current.target]; %>' +
'/* <%= subtask.name %> <%= pkg.version %> (<%= grunt.template.today("yyyy-mm-dd, HH:MM") %>)\n' +
' */\n'
},
main: {
name: 'main.min.js',
files: [{
src: 'build/files/js/main.min.js',
dest: 'build/files/js/main.min.js'
}]
},
vendor: {
name: 'vendor.min.js',
files: [{
src: 'build/files/js/vendor.min.js',
dest: 'build/files/js/vendor.min.js'
}]
}
}
Try the following:
banner: grunt.file.read('./folder/file.js'),
https://stackoverflow.com/questions/38854998/dynamic-mapping-and-concat-with-grunt-uglify/
https://github.com/mattstyles/grunt-banner/issues/5#issuecomment-33445038
process: function (src, filepath) {} did the job.
For me, I wanna add "//# sourceUrl=xxx.min.js" at the bottom of each uglified .min.js so that I can debug these dynamically loaded .min.js. The following simple Gruntfile.js works for me:
module.exports = function (grunt) {
var cwd = "/Branding/Layouts/JS/";
var src = [
"file1.js",
"file2.js",
"file3.js"
];
var minified_src = [];
for (i=0; i< src.length; i++)
minified_src.push(src[i].replace(/\.js$/g, ".min.js"));
var config = grunt.initConfig({
"uglify": {
options: {
sourceMap: true
},
target: {
files: [
{
expand: true,
cwd: cwd,
src: src,
dest: cwd,
ext: ".min.js",
extDot: "last"
}
]
}
},
concat: {
options: {
process: function (src, filepath) {
return src + "\n//# sourceURL=" + filepath.split("/").slice(-1);
}
},
target: {
files: [
{
expand: true,
cwd: cwd,
src: minified_src,
dest: cwd
}
]
}
}
});
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.registerTask('default', ['uglify', 'concat']);
};
Note: uglify can't preserve a comment that is not inside a code block (like //# sourceMap=xxx.js), I have to use concat to append the comment after uglify is done.
Wow, this is my first stackoverflow post.
Documentation is indeed scarse, but <%= pkg.name %> in the banner string implies you can also do <% for ( var s in grunt) { %> \ngrunt.<%=s%><% } %> or even <% for ( var s in this) { %> \nthis.<%=s%><% } %>.
So (after some searching) to get the filename you can do this:
var bannerTemplate = '<%'
+' var subtask = uglify[grunt.task.current.target];'
+' var file = subtask?subtask.dest:\'\';'
+' var filename = file.split(\'/\').pop();'
+'%>'
+'/*! <%= filename %>'
+'\n * version: <%= pkg.version %>'
+'\n * author: <%= pkg.author %>'
+'\n */\n';

Grunt concat not working during watch task

If I run 'grunt concat' it compiles my JS files as per the Grunt file (line 82). However, it doesn't concatenate when I'm doing 'grunt watch' (line 107).
From what I can see, my file is ok but I'm fairly new to grunt so would love to see if you guys can see an issue.
Here is my full Grunt file...
// All scripts to be included in project go here
var _SCRIPTS = [
'js/prefixfree.js',
'js/jquery-1-10-2.js',
'js/ie-detect.js',
'js/application.js'
];
var _PORT = 7777;
module.exports = function(grunt) {
// load all grunt tasks
require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
connect: {
server: {
options: {
port: _PORT,
base: 'prototype'
}
}
},
htmlvalidation: {
options: {
},
files: {
src: ['prototype/*.php']
},
},
jshint: {
beforeconcat: _SCRIPTS,
afterconcat: ['js/main.js']
},
csslint: {
check: {
src: ['css/*.css']
},
strict: {
options: {
import: 2
},
src: ['css/*.css']
},
lax: {
options: {
import: false
},
src: ['css/*.css']
}
},
compass: {
dev: {
options: {
config: 'config.rb',
force: false
}
}
},
uglify: {
options: {
banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n'
},
dist: {
files: {
'js/main.js': ['js/main.js']
}
}
},
concat: {
options: {
stripBanners: true,
banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - ' +
'<%= grunt.template.today("yyyy-mm-dd") %> */',
},
dist: {
src: _SCRIPTS,
dest: 'js/main.js',
nonull: true
},
},
cssmin: {
add_banner: {
options: {
banner: '/* <%= pkg.name %> - v<%= pkg.version %> - ' +
'<%= grunt.template.today("yyyy-mm-dd") %> */',
},
files: {
'css/style.css': ['css/style.css']
}
}
},
watch: {
concat: {
files: ['js/**/*.js', '!js/main.js'],
tasks: 'concat',
options: {
spawn: false,
},
},
sass: {
files: ['sass/**/*.scss'],
tasks: ['compass:dev'],
options: {
spawn: false,
},
},
/* watch and see if our javascript files change, or new packages are installed */
/* watch our files for change, reload */
livereload: {
files: ['*.html', 'css/*.css', 'img/*', 'js/*.js'],
options: {
livereload: true
}
},
}
});
// Default task (Watch)
grunt.registerTask('default', ['watch']);
// grunt.registerTask('default', [ 'preprocess:dev', 'watch']);
// Watch with localhost (For Static Templates)
grunt.registerTask('watch_with_server', [ 'connect:server', 'watch']);
// TESTING
// Run all tests
grunt.registerTask('allTests', [ 'jshint:beforeconcat', 'concat', 'jshint:afterconcat', 'cssLint', 'htmlvalidation']);
// JS Testing
grunt.registerTask('jsHint', ['jshint:beforeconcat', 'concat', 'jshint:afterconcat']);
// CSS Testing csslint
grunt.registerTask('cssLint', ['csslint:check']);
grunt.registerTask('cssLintLax', ['csslint:lax']);
grunt.registerTask('cssLintStrict', ['csslint:strict']);
// HTML Vaidation
grunt.registerTask('htmlTest', [ 'htmlvalidation']);
grunt.registerTask('printenv', function () { console.log(process.env); });
// Concat and uglify js and minify css for release
grunt.registerTask('release', [ 'concat:dist', 'uglify', 'cssmin']);
};
Many thanks
I managed to get it working by moving 'livereload' above 'concat' in the watch task. No idea why this would make a difference but it's working!
If anyone has any insight on why this would affect it I'd love to know.
add this and see:
livereload: {
files: ['*.html', 'css/*.css', 'img/*', 'js/*.js'],
options: {
livereload: true
}
},
options: {
livereload: true
},
files: '<%= options.watch.files %>',//might have to change this line
tasks: ['default', 'notify:watch']

Changing grunt uglify config options on watch

I'm trying to alter my default uglify dev options on 'watch', however they're not getting set. I'm planning on adding more subtasks to the uglify task for 'production' as an example, which will use the default options, however for my 'dev' subtask, i'd like to pass new options with the watch task.
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
// ...
uglify: {
// default options
options: {
banner: '<%= banner %>/* Built <%= grunt.template.today("yyyy/mm/dd") %> for <%= powerful.name %> */\n',
preserveComments: 'some',
report: 'min',
mangle: {
except: ['jQuery', 'Backbone']
}
},
dev: {
// options were here...
files: {
// Powerful Theme JS
'<%= powerful.jspath %>touch.min.js':
[
'<%= powerful.jspath %>libs/jquery.hammer.js',
'<%= powerful.jspath %>dev/touch.js'
],
'<%= powerful.jspath %>768down.min.js':
[
'<%= powerful.jspath %>dev/768down.js'
]
}
},
production: {
// production files here, use default options....
}
},
watch: {
js: {
files: ['<%= themesPath %>/**/js/{dev,libs,bootstrap}/*.js'],
tasks: ['uglify:dev'],
options: {
nospawn: true
}
}
}
});
// ...
grunt.event.on('watch', function(action, filepath) {
grunt.config.set('uglify.dev.options', {
banner: '/*! TESTING 123 */',
preserveComments: 'all',
report: false,
compress: false,
beautify: true
});
});
grunt.registerTask('default', ['watch']);
};

Grunt Multitask configuration issues

I'm trying to configure a grunt file that can run multiple tasks on multiple "themes". Since i'm new to this whole grunt thing, i'm having some problems with the configuration.
My example below is just a start, but essentially I'd like to have some global configs, and then nest specific "theme" configurations within a named "target". I'm not fully up to speed on syntax, so that could be the issue, but when I run grunt powerful I get the error Warning: Required config property "watch" missing? I feel that the configs are ok, but the problem lies with my registerMultiTask. Any ideas?
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
// Metadata.
pkg: grunt.file.readJSON('package.json'),
banner: '/*!\n' +
'* Microsites v<%= pkg.version %>\n' +
'* Copyright <%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' +
'*/\n' +
'/* #package: <%= pkg.name %> */\n',
jqueryCheck: 'if (!jQuery) { throw new Error(\"<%= pkg.name %> requires jQuery\") }\n\n',
basePath: '../../www/wp-content/themes',
powerful: {
name: 'Powerful Theme',
path: '<%= basePath %>/powerful',
less: {
development: {
options: {
dumpLineNumbers: true
},
files: {
'<%= powerful.path %>/static/css/project.css': '<%= powerful.path %>/static/css/less/project.less',
'<%= powerful.path %>/static/css/editor.css': '<%= powerful.path %>/static/css/less/editor.less',
'<%= powerful.path %>/static/css/login.css': '<%= powerful.path %>/static/css/less/login.less'
}
},
production: {
options: {
yuicompress: true
},
files: {
'<%= powerful.path %>/static/css/project.css': '<%= powerful.path %>/static/css/less/project.less',
'<%= powerful.path %>/static/css/editor.css': '<%= powerful.path %>/static/css/less/editor.less',
'<%= powerful.path %>/static/css/login.css': '<%= powerful.path %>/static/css/less/login.less'
}
},
ie: {
options: {
yuicompress: true
},
files: {
'<%= powerful.path %>/static/css/ie.css': '<%= powerful.path %>/static/css/less/ie.less'
}
}
},
watch: {
less: {
files: ['<%= powerful.path %>/static/css/less/*.less'],
tasks: ['less:development']
}
}
}, // end: powerful
});
// load the plugin
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-concat');
// load tasks
//grunt.registerTask('default', ['less']);
grunt.registerMultiTask('powerful', 'do things', function(){
grunt.task.run(['watch']);
});
};
Tasks should go on the first level of your config, not within another task config. Also your powerful task isnt a multitask so it doesnt even need a config block. Just configure the tasks the standard way:
grunt.initConfig({
less: {
/* config here */
},
watch: {
/* config here */
}
});

Using Grunt to set environment based variables

I'm looking at grunt-string-replace to accomplish changing variables in my files to an environment specific variable. However, when I try to run the grunt script below I get this warning: "Task min:dev not found". But in this code I have that defined:
module.exports = function (grunt) {
// Project configuration.
grunt.initConfig({
min: {
dev: {
"string-replace": {
dist: {
files: {
"/newrelic.js": "/newrelic.js"
},
options: {
replacements: [
{
pattern: /$APPNAME/ig,
replacement: "services"
},
{
pattern: /$ENV/ig,
replacement: "nonprod"
}
]
}
}
}
},
prod: {
pkg: grunt.file.readJSON('package.json'),
uglify: {
options: {
banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
},
build: {
src: 'src/<%= pkg.name %>.js',
dest: 'build/<%= pkg.name %>.min.js'
}
}
}
}
});
// Load the plugin that provides the "uglify" task.
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-string-replace');
// Default task(s).
grunt.registerTask('default', ['min:dev']);
grunt.registerTask('prod', ['min:prod']);
};
Am I missing something?
Have you read the manual? The getting started guide states that the tasks expect their configuration to be specified in a property of the same name. You have no 'min' task defined, thus it's erroring.
The top-level keys of the config object need to match the task names, and then you define 'targets' (eg, 'dev' or 'prod') within the task config.
So, here's your Gruntfile re-worked. I have not tested this so I can't promise it will work, but it will certainly lead you in the right direction:
module.exports = function (grunt) {
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
"string-replace": {
dev: {
files: {
"/newrelic.js": "/newrelic.js"
},
options: {
replacements: [{
pattern: /$APPNAME/ig,
replacement: "services"
}, {
pattern: /$ENV/ig,
replacement: "nonprod"
}]
}
}
},
uglify: {
prod: {
options: {
banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
},
build: {
src: 'src/<%= pkg.name %>.js',
dest: 'build/<%= pkg.name %>.min.js'
}
}
}
});
// Load the plugin that provides the "uglify" task.
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-string-replace');
// Default task(s).
grunt.registerTask('default', ['string-replace:dev']);
grunt.registerTask('prod', ['uglify:prod']);
};
think your trying to do this, this fragment will put the environment variable SOME_ENV, into the grunt config, the replace is simply giving you a easy way to do ${SOME_ENV} placeholders in files for replacement
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
pkg : grunt.file.readJSON('package.json'),
SOME_ENV: process.env.SOME_ENV,
copy: {
files: [
{expand: true, cwd: "src/", src: ["*.*", "**/*.*"], dest: "./build",}
],
options: {
// Replace ${MEH} in files with grunt.config.get("MEH"),
// eg ${SOME_ENV}
// == grunt.config.get("SOME_ENV")
// == process.env.SOME_ENV == systems SOME_ENV environment var
process: function (content, srcpath) {
return content.replace(
/\$\{([a-zA-Z.]+)\}/g,
function replacer(match, p1, offset, string){
var value = grunt.config.get(p1);
grunt.log.write(" in file '" + srcpath + "'\n replacing '" + match + "'\n with '" + value + "'\n");
return value;
});
}
},
}
});
// Production Build Tools
grunt.loadNpmTasks('grunt-contrib-copy');
// Default Production Build task(s).
grunt.registerTask('default', ['copy']);
};

Resources