I'm running a grunt concat task on one of my projects and it looks something like this:
/**
* Concatenate | Dependencies Scripts
*/
concat: {
dependencies: {
files: {
"./Ditcoop/js/plugins.min.js": ["./Ditcoop/js/vendor/**/*.min.js", "!./Ditcoop/js/vendor/modernizr/*.js", "!./Ditcoop/js/vendor/jquery/*.js"],
"./Global/js/plugins.min.js": ["./Global/js/vendor/**/*.min.js", "!./Global/js/vendor/modernizr/*.js", "!./Global/js/vendor/jquery/*.js"],
"./Webshop/js/plugins.min.js": ["./Webshop/js/vendor/**/*.min.js", "!./Webshop/js/vendor/modernizr/*.js", "!./Webshop/js/vendor/jquery/*.js"]
}
}
}
My question would be if I could somehow make that more dynamic without having to specify each root folder. I was thinking of something like this:
concat: {
dependencies: {
files: {
"./*/js/plugins.min.js": ["./*/js/vendor/**/*.min.js", "!./*/js/vendor/modernizr/*.js", "!./*/js/vendor/jquery/*.js"],
}
}
}
I'm pretty sure I cannot do it this way, but I could use the expand option, I'm just not sure how I could use it so I can do that under the right root folder, so I won't create the same destination file as many times I run the concat.
Always remember Gruntfiles are javascript :)
grunt.initConfig({
concat: {
dependencies: {
files: (function() {
var files = Object.create(null);
grunt.file.expand({filter: 'isDirectory'}, '*').forEach(function(dir) {
files[dir + '/js/plugins.min.js'] = [
dir + '/js/vendor/**/*.min.js',
'!' + dir + '/js/vendor/modernizr/*.js',
'!' + dir + '/js/vendor/jquery/*.js'
];
});
return files;
}()),
},
},
});
But if your dependency handling logic is this complex you may want to consider using a module loader such as browserify or requirejs. The concat task is really just for joining simple files together.
Related
I am using save2png to provide fallback pngs to svg4everybody. The svgs are created and I can change input and output directory. But svg4everybody requires that the pngs are saved with a filename like: "spritesheetname.svg.id.jpg"
At first, I tried some simple things, but I can't even figure out how to change the filename in the first place.
Here is my code:
module.exports = function(grunt){
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
svg2png: {
all: {
files: [
// rasterize all SVG files in "img" and its subdirectories to "img/png"
{ cwd: '../img/icons/',
src: ['**/*.svg'],
dest: '../symbol/svg/',
rename: function(dest, src) {
var filename = src.substring(src.lastIndexOf('/'), src.length);
return dest + 'prefix' + filename + '.png';
}
}
]
}
}
});
grunt.registerTask('default', []);
grunt.loadNpmTasks('grunt-svg2png');
};
The pngs are created, but the filename is always the same as the original svg.
I stumbled upon this question, Grunt rename not working, but it was no real help. Flatten and expand just changed the directory structure, but had no influence on the filename.
I'm using load-grunt-config to split my gruntfile and I have a requirement to access the variables of one task in another. The tasks are being exported using module.exports. Is it possible to access job variables in one task from another task that runs after it?
module.exports= function(grunt) {
combine: {
files: {
'dist/lib.min.css' : ['file1', 'file2']
}
}
}
module.exports = function (grunt) {
for (var file in //grunt.combine.files???
//do stuff with files
}
It looks like you are in need of a shared configuration between two tasks.
load-grunt-config exposes the 'data' object that lets you tweak the grunt configuration.
module.exports = function(grunt) {
require('load-grunt-config')(grunt, {
// data passed into config.
data: {
files: ['file1', 'file2']
}
});
}
that you can later use, in your example, as such
module.exports = function(grunt) {
combine: {
files: {
'dist/lib.min.css' : '<%= files %>'
}
}
}
module.exports = function (grunt) {
for (var file in grunt.config('files')) {
//do stuff with files
}
}
I'm trying to encrypt my .keychain files on my Mac and saving them on in a backup place. When i run grunt enc it just creates 2 very small files in the directory of the source files. So encrypting and moving the files doesn't go well...
package.js is just grunt with 1 devDependency grunt-encrypt.
Gruntfile.js is shown below.
'use strict';
module.exports = function(grunt) {
var npmDependencies = require('./package.json').devDependencies;
grunt.initConfig({
encrypt: {
encryptKeys: {
options: {
key: 'SuperSecretKey',
dest: '/Users/myusername/www/admin/filebackup/encrypted',
},
files: {
'keychains': [
'/Library/Keychains/system.keychain',
'/Users/myusername/Library/Keychains/login.keychain'
]
}
}
},
});
grunt.loadNpmTasks('grunt-encrypt');
grunt.registerTask('enc', [
'encrypt'
]);
};
I've been using Grunt for a week, so could very well be i'm missing something obvious. Anybody used grunt-encrypt before?
Thanks!
Looks as if your SuperSecretKey is not defined yet.
I've solved it like this:
add
module.exports = function (grunt) {
// ad here
var superSecretKey = 'secretpassword';
to your Gruntfile.js
Or put a keyfile (mine is called livereload.key) in the project's root and alter your Gruntfile like this:
//key : superSecretKey,
key: grunt.file.read('livereload.key'),
I have a grunt file with the following definition:
uglify: {
build: {
src: 'www/temp/application.js', // a concatenation of files via grunt-contrib-concat
dest: 'www/temp/application.min.js'
}
},
what I would really like to do is to recompute the final application.min.js only in case that application.js file was changed. More precisely, I want to add the condition:
# pseudocode
if (getFileContents(application.js) == getFileContents(previously.uglified.application.js)) {
// do nothing
} else {
// run uglifying on application.js
}
Reason:
I deploy my project by git and uglifying is relatively slow (3+ seconds) and moreover, it is unnecessary since I don't change JS files often.
There are several possible solutions:
You can create your own grunt task that will check files for last modify time using for example fs.stat then run uglify task through grunt.task.run with prepared options as argument.
Or you can build files object dynamically passing it through filter function:
var fs = require('fs');
module.exports = function (grunt) {
function filterChanged(files) {
var mtime = '',
stats;
for (var dest in files) {
stats = fs.statSync(files[dest]);
try {
mtime = fs.readFileSync(files[dest] + '.mtime', 'utf8');
}
catch (ex) {
fs.writeFileSync(files[dest] + '.mtime', stats.mtime, 'utf8');
return files;
}
if (stats.mtime == mtime || !mtime) {
delete files[dest];
}
else {
fs.writeFileSync(files[dest] + '.mtime', stats.mtime, 'utf8');
}
}
return files;
}
grunt.initConfig({
uglify: {
build: {
files: filterChanged({
'www/temp/application.min.js': 'www/temp/application.js'
})
}
}
});
};
This causes invoke of filterChanged function every time uglify task runs.
I'm trying to figure out a way to break out a watch target from the rest of the block. Currently my watch target looks like this:
watch: {
options: {
// Parent-level options
},
coffee: {
// ...
},
stylus: {
// ...
},
test: {
options: {
// Test-specific options
},
files: {
// ...
}
tasks: {
// ...
}
}
}
The problem I'm facing is that my test options include a different livereload port than the top level, so I can simultaneously run grunt server and grunt test with livereloading and not have them interfere with each other.
Beneath that, I have a server alias and a test alias. What I'm looking for is to break the test watch target out into another task so I can simply run watch in my server alias and something like watch-test for testing, such that the server task doesn't run the test target.
Any ideas? Please let me know if I've left out anything important or this isn't clear.
Thanks!
A solution I've used is to define multiple watch targets and rename the watch task like so:
watch: {
scripts: {
files: ['js/**/*.js'],
tasks: ['concat', 'uglify'],
options: {
spawn: false
}
}
},
// Don't uglify in dev task
watchdev: {
scripts: {
files: ['js/**/*.js'],
tasks: ['concat'],
options: {
spawn: false
}
}
}
grunt.loadNpmTasks('grunt-contrib-watch');
// Rename watch to watchdev and load it again
grunt.renameTask('watch', 'watchdev');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.registerTask('default', ['watch']);
grunt.registerTask('dev', ['watchdev']);
Since grunt watch is a multi task, running grunt watch from the CLI means that all targets are watched. You can instead run one target out of those by simply running grunt watch:test or grunt watch:server, whatever is your preference. Hope that helps.
Edit: It might be appropriate to point out this issue on the watch issue tracker:
https://github.com/gruntjs/grunt-contrib-watch/issues/206
The code in the issue is a little old, I would recommend newer code to require lodash and use _ instead of grunt.util._ (that utility is now deprecated). So the code would look like this:
var _ = require('lodash');
module.exports = function(grunt) {
// Run with: grunt switchwatch:target1:target2 to only watch those targets
grunt.registerTask('switchwatch', function() {
var targets = Array.prototype.slice.call(arguments, 0);
Object.keys(grunt.config('watch')).filter(function(target) {
return !(_.indexOf(targets, target) !== -1);
}).forEach(function(target) {
grunt.log.writeln('Ignoring ' + target + '...');
grunt.config(['watch', target], {files: []});
});
grunt.task.run('watch');
});
}
Still, you could modify your server task to run something like switchwatch:coffee:stylus:server:
grunt.registerTask('server', [/* rest of your tasks */, 'switchwatch:coffee:stylus:server']);