Grunt: sending array of sourceFiles to grunt task uglify - gruntjs

I can't seem to find the answer in the documentation. I want to send an array of sourceFiles from my package.json to the grunt task.
Here is my config.json
{
"sourceFiles": ["src/js/d3js/d3.js", "src/js/testingGrunt.js"]
}
and here is my gruntfile.js
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
config: grunt.file.readJSON('config.json')
});
// Load the plugin that provides the concat tasks.
grunt.loadNpmTasks('grunt-contrib-concat');
// defining my concat task
grunt.config('concat', {
dist: {
//src: ['src/js/testingGrunt.js', 'src/js/d3js/d3.js'],
src: '<%config.sourceFiles%>',
dest: 'build/<%= pkg.name %>-build.js'
}
});
// Load the plugin that provides the uglify tasks.
grunt.loadNpmTasks('grunt-contrib-uglify');
// defining my uglify task
grunt.config('uglify', {
options: {
banner: '/*\n* ©<%= pkg.author%>\n* <%= pkg.name %>\n* <%= grunt.template.today("yyyy-mm-dd HH:mm:ss") %> \n*/\n'
},
build: {
src: 'build/<%= pkg.name %>-build.js',
dest: 'build/<%= pkg.name %>-build.min.js'
}
});
// Default task(s).
var defaultTasks;
defaultTasks = ['concat', 'uglify']
grunt.registerTask('default', defaultTasks);
};
The commented out line inside the grunt.config('concat',... works just fine. However I want to set up my gruntfile to read the files from the config file.
Eventually I'm going to be doing other things in this grunt task and I want to set it up so that I never need to edit the grunt file.

Looks like the template syntax is off try replacing:
src: '<%config.sourceFiles%>',
with the following:
src: '<%= config.sourceFiles %>',

Related

How to use array variable properly in gruntfile.js

Trying to use a predefined array inside of a grunt file, thought using this.js_paths would work, but doesn't seem to work as I'm getting the error, "Cannot read property IndexOf of undefined" when it comes to trying to uglify the scripts. How can I link the js_paths variable to the files src property properly instead of copying the array into the files. Would like to define it separately at the top. Is this possible?
module.exports = function(grunt) {
// loadNpmTasks from package.json file for all devDependencies that start with grunt-
require("matchdep").filterDev("grunt-*", './package.json').forEach(grunt.loadNpmTasks);
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
js_paths: [
'inc/header1/js/*.js',
'!inc/header1/js/*.min.js',
'inc/header2/js/*.js',
'inc/header2/js/*.js',
'!inc/header2/js/*.min.js',
'js/*.js',
'!js/*.min.js'
],
uglify: {
options: {
mangle: true
},
build: {
files: [{
expand: true,
src: this.js_paths,
rename: function(dst, src) {
return src.replace('.js', '.min.js');
}
}]
}
},
watch: {
scripts: {
files: ['inc/header1/js/*.js', 'inc/header2/js/*.js', 'js/*.js'],
tasks: ['uglify'],
options: {
spawn: false,
}
}
}
});
grunt.registerTask('default', ['uglify', 'watch']);
};
Preferrably would like to use the same array js_paths in the watch files (since it's required there), if that makes sense? Still kinda new to using gruntfile.js
Utilize the Templates syntax. It's described in the docs as following:
Templates
Templates specified using <% %> delimiters will be automatically expanded when tasks read them from the config. Templates are expanded recursively until no more remain.
Essentially, change this.js_paths to '<%= js_paths %>' in your uglify task.
For instance:
// ...
uglify: {
options: {
mangle: true
},
build: {
files: [{
expand: true,
src: '<%= js_paths %>', // <-----
rename: function(dst, src) {
return src.replace('.js', '.min.js');
}
}]
}
},
// ...
Likewise for your watch task too.
For instance:
watch: {
scripts: {
files: '<%= js_paths %>', // <-----
tasks: ['uglify'],
options: {
spawn: false,
}
}
}

grunt watch task is not watching js files just says waiting

I have been trying to configure this gruntfile for days, I have seen and read multiple documents on how to set it up. I have been able to set it up so I can run individual tasks by typing in the individual commands into bash:
grunt uglify
grunt sass
grunt cssmin
However grunt watch seems to not watch any of my js files
All of which work fine, but when I tried to run them all under the "watch" task, my js files are all ignored. my command line just reads 'waiting...'. Changing any of the content in my js files does not trigger an update. I also had toruble running jshint as it kept telling me that it is looking for a string etc. so i disabled that plugin for now. Here is my file:
module.exports = function (grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
sass: { // Task
dist: { // Target
files: { // Dictionary of files
'assets/css/style.css': 'assets/scss/style.scss'
// 'destination': 'source'
}
}
},
cssmin: {
options: {
banner: '/*\n <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd")
%> \n*/\n'
},
build: {
files: {
'assets/css/style.min.css': 'assets/css/style.css'
}
}
},
uglify: {
options: {
banner: '/*\n <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd")
%> \n*/\n'
},
build: {
files: {
'assets/js/magic.min.js': ['assets/js/magic.js',
'assets/js/server.js', 'assets/js/script.js']
}
}
},
// configure jshint to validate js files -------------------------------
// jshint: {
// options: {
// reporter: require('jshint-stylish')
// },
// // when this task is run, lint the Gruntfile and all js files in
src
// build: ['Gruntfile.js', 'assets/**/*.js']
// },
watch: {
// for stylesheets, watch css and less files
// only run less and cssmin stylesheets: {
files: ['assets/**/*.css', 'assets/**/*.less'],
tasks: ['sass', 'cssmin']
},
// for scripts, run jshint and uglify
scripts: {
files: 'assets/**/*.js',
tasks: 'uglify'
}
});
// Default tasks
//grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-concurrent');
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-contrib-sass');
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.registerTask('default', ['uglify', 'cssmin', 'sass', 'watch']);
};
I think you want to do this ?
watch: {
stylesheets: {
files: ['assets/**/*.css', 'assets/**/*.less'],
tasks: ['sass', 'cssmin']
},
// for scripts, run jshint and uglify
scripts: {
files: 'assets/**/*.js',
tasks: 'uglify'
}
}

grunt-depend-concat is not replace #depend tags with file contents

I'm trying to use grunt-depend-concat to create a site.uncompressed.js file with the contents of all the dependencies using #depend tags in my site.js file. The destination file is being created, but the #depend comments are still at the top of the file. Am I using this grunt package correctly? Is there a problem with my code? I'm open to alternative Grunt packages if I can still use #depend tags, but the grunt package documentation is rather sparse and I can figure out how else it might be possible to do this.
site.js (partial):
/**
* #depend vendor/jquery-1.11.1.min.js
* #depend vendor/jquery.smooth-scroll-1.4.13.min.js
[…]
*/
[…]
Gruntfile.js:
(function () {
'use strict';
}());
module.exports = function (grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
filepaths: {
assetDir: 'httpdocs/files/assets/',
jsDir: '<%= filepaths.assetDir %>' + 'js/',
jsSrc: '<%= filepaths.jsDir %>' + 'site.js',
jsComb: '<%= filepaths.jsDir %>' + 'site.uncompressed.js',
jsMin: '<%= filepaths.jsDir %>' + 'site.min.js';
},
'depend-concat': {
depend_doctag: {
options: {
method: {
type: 'doctag',
tag: 'depend'
}
},
src: ['<%= filepaths.jsSrc %>'],
dest: '<%= filepaths.jsComb %>'
},
},
uglify: {
options: {
preserveComments: false,
banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */',
sourceMap: true
},
dist: {
files: {
'<%= filepaths.jsMin %>': ['<%= filepaths.jsComb %>']
}
}
}
});
require('load-grunt-tasks')(grunt);
grunt.registerTask('default', ['jshint', 'depend-concat', 'uglify']);
};
Grunt Output:
Running "jshint:files" (jshint) task
>> 2 files lint free.
Running "depend-concat:depend_doctag" (depend-concat) task File
"httpdocs/files/assets/js/site.uncompressed.js"
created.
Running "uglify:dist" (uglify) task
>> 1 sourcemap created.
>> 1 file created.
Done, without errors.
site.uncompressed.js (partial):
/**
* #depend vendor/jquery-1.11.1.min.js
* #depend vendor/jquery.smooth-scroll-1.4.13.min.js
[…]
*/
Unfortunately, I have not been able to get this Grunt plugin to work properly, so I have given up on using grunt-depend-concat with #depend rules in the site.js file.
I added a section to filepaths in the Gruntfile, then used the grunt-contrib-concat plugin instead.

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';

Where are JSHint errors logged?

I just started messing around with Grunt. I have a basic implementation running successfully, minifying my code and running JSHint.
It says 0 files lint free, which I've gathered means that all of the files it's checking have lint.
However, I've been googling for an hour, and somehwat incredibly, cannot figure out where the hell these errors are being saved.
Do I need to specify a logfile in the grunt config? I don't see anything like that in the JSHint or grunt documentation.
Gruntfile below, taken pretty much straight from Grunt's "Getting Started". I pulled out qunit because I don't currently have any tests -
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
concat: {
options: {
// define a string to put between each file in the concatenated output
separator: ';'
},
dist: {
// the files to concatenate
src: ['spin/**/*.js'],
// the location of the resulting JS file
dest: 'dist/<%= pkg.name %>.js'
}
},
uglify: {
options: {
// the banner is inserted at the top of the output
banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n'
},
dist: {
files: {
'dist/<%= pkg.name %>.min.js': ['<%= concat.dist.dest %>']
}
}
},
jshint: {
// define the files to lint
files: ['gruntfile.js', 'src/**/*.js', 'test/**/*.js'],
// configure JSHint (documented at http://www.jshint.com/docs/)
options: {
// more options here if you want to override JSHint defaults
"curly": true,
"eqnull": true,
"eqeqeq": true,
"undef": true,
globals: {
jQuery: true,
console: true,
module: true
}
}
},
watch: {
files: ['<%= jshint.files %>'],
tasks: ['jshint']
}
});
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.registerTask('test', ['jshint']);
grunt.registerTask('default', ['jshint', 'concat', 'uglify']);
};
0 files lint free does not mean that you have files which have errors, it means that zero files are checked!
the jshint-task will output errors to your console (including file, linenumber and column)
thats where you specify your files to check:
files: ['gruntfile.js', 'src/**/*.js', 'test/**/*.js'],
if you change 'gruntfile.js' to 'Gruntfile.js' (case sensitive!) it should check your gruntfile (which you of course already have).

Resources