Grunt - Concat multiple JS files and watch for changes - javascript

Still a bit of a newbie with Grunt, so please bear that in mind with your answers. I am trying to setup a task in Grunt that will concat any JS files within a directory called "custom", into a single file called custom-concat.js, however after running grunt watch (which runs fine without error), nothing is happening when I try and make changes to any of the files within my "custom" directory (i.e. console just sits at "waiting...." even after I make changes to any JS files within "custom" directory). Clearly there is something wrong with my concat task, but I can't seem to see what the problem is. Can anyone see where the problem lies? Full gruntfile below:
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
//pkg: grunt.file.readJSON('package.json'),
concat: {
options: {
separator: ';',
},
dist: {
src: ['scripts/custom/**/*.js'],
dest: 'scripts/custom-concat.js',
},
},
uglify: {
build: {
src: 'scripts/custom-concat.js',
dest: 'scripts/custom.min.js'
}
},
less: {
options: {
paths: ["css"]
},
files: {
"styles.css": "less/styles.less"
}
},
watch: {
scripts: {
files: 'scripts/**/*.js',
task: ['concat', 'uglify:build']
},
styles: {
files: 'css/less/**.less',
task: 'less'
}
}
});
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-watch');
// Default task(s).
grunt.registerTask('default', ['concat', 'uglify']);
};

As far as I see, there are three small issues with your watch task:
The correct attribute for watch is taskS not task
If you want to run the tasks of watch, directly at the beginning, use options { atBegin: true }
Your watch task monitors the script folder. However, this folder will also contain your concated and uglified files. So this task will run into an infinite loop. You should probably only watch the scripts/custom folder
So your watch task should probably look something like this:
watch: {
scripts: {
files: 'scripts/custom/**/*.js',
tasks: ['concat', 'uglify:build'],
options: {
atBegin: true
}
},
styles: ...
}
Github grunt-contrib-watch

Related

Error: ENOENT in Grunt uglify task

I have the following gruntfile.js. Using grunt-contrib-concat and grunt-contrib-uglify together.
This is an extention of a developement asked #Dynamic Mapping and Concat with Grunt Uglify
I use banner in the uglify task to reference a file created in the concat task.
module.exports = function(grunt){
// Configure task(s)
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
// setup concats
concat: {
options: {
separator: ';\n',
},
dev: {
files: [{
src: [
'sports.js',
'salon.js',
'offRoad.js',
],
dest: 'src/js/concat/car-dev.js'
}],
},
},
// setup uglify task
// this will produce a car js file (which includes car-dev.js) for every car js file located within scr/js/cars/
uglify: {
// dev - use in development mode, global overrides section
dev: {
options: {
// include concat dev.js
banner: grunt.file.read('src/js/concat/car-dev.js'),
beautify: true,
mangle: false,
compress: false,
preserveComments: 'all'
},
files: [{
expand: true,
cwd: 'src/js/cars/',
src: '*.js',
dest: 'javascript/dev',
ext: '.dev.js',
extDot: 'first'
}],
},
},
});
// Load the plugins
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-sass');
// Register task(s)
grunt.registerTask('default',
'concat:dev'
'uglify:dev'
]);
};
My issue is that if src/js/concat/car-dev.js doesn't exist, I get the following error:
Error: Unable to read "src/js/concat/car-dev.js" file <Error code: ENOENT).
If I create an empty file #src/js/concat/car-dev.js the grunt command works fine.
However this is not always possible. I want uglify to reference the car-dev.js file even if it doesn't exist. What I'm looking for is someway to reference the grunt->concat->dev->files->dest file.
I've tried adding the following
banner: grunt.file.read(grunt.concat.dev.files.dest),
and
banner: grunt.concat.dev.files.dest
but neither work. Is this possible?
This is not a task dependency issue - the error gets thrown before any tasks are run because banner: src/js/concat/car-dev.js does not exist.
Any help - much appreciated.

Grunt watch pattern.indexOf is not a function

I'm trying to use Grunt's grunt-contrib-watch plugin to watch some files and then run the tasks, just what it was made for, this is my Gruntfile.js
module.exports = function(grunt){
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
sass: {
options: {
sourceMap: true,
outputStyle: 'compressed'
},
dist: {
files: {
'static/stylesheets/main.min.css': 'static/stylesheets/sass/main.scss',
/*'bower_components/foundation-sites/dist/foundation.min.css': 'bower_components/foundation-sites/scss/foundation.scss'*/
}
}
},
uglify: {
dist: {
files: {
'static/javascript/main.min.js': 'static/javascript/main.js'
}
}
},
watch: {
files: [
'<%= sass.dist.files %>',
'<%= uglify.dist.files %>'
],
tasks: [
'sass',
'uglify'
]
}
});
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-sass');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.registerTask('default', ['watch']);
};
When I run it, it runs over and over and over again, and when I stop it, I see I have this message:
Running "watch" task
Waiting...
Warning: pattern.indexOf is not a function
I really don't know what's the problem. Does anybody know what happens here?
UPDATE:
Apparently, the problem is because of the way I call the files, because I changed it to: 'static/stylesheets/sass/*.scss' and it worked well, but I would like to know why the other way doesn't work, because I think is a more useful way to do it.
grunt-contrib-watch expects either a single pattern string or an array of pattern strings as the value of its files config. However, the templates you are using in your config evaluate to objects. Your watch.files value evaluates to the following:
files: [
{ 'static/stylesheets/main.min.css': 'static/stylesheets/sass/main.scss' },
{ 'static/javascript/main.min.js': 'static/javascript/main.js' }
]
When the pattern matching tries to run it fails because there is no indexOf method on an Object. Due to the fact that grunt-contrib-watch runs forever, there is an infinite loop of the trying and failing to build the list of watched files.
You would normally configure your watch files with something like the following:
files: [
'static/**/*.scss',
'static/**/*.js'
]
But the above will cause issues in your case because your minified JS file is in the same folder as your source JS file. You could probably get around this by adding '!static/**/*.min.js' to your files array, but a better solution would be to put all of your compiled files into a separate folder.
Extract the values from the object:
watch: {
files: [
'<%= sass.dist.files.values() %>',
'<%= uglify.dist.files.values() %>'
],

Referencing a module / script when using npm and grunt

I'm looking into npm, grunt and bower, and I've made my first task which looks like this.
module.exports = function(grunt){
grunt.initConfig({
concat: {
options: {
separator: ';',
},
dist: {
src: ['node_modules/jquery/dist/jquery.js', 'node_modules/handlebars/dist/handlebars.js'],
dest: 'dist/scripts.js',
},
},
});
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.registerTask('default', ['concat']);
};
I was wondering if there's an easier/better way of adding the scripts. So that instead of typing the whole path you could just do src: [jquery, 'handlebars'],
and if bower is of any use regarding this?
Thank you.

using grunt-contrib-concat with bower

i have this situation:
i have some js libraries downloaded via bower in bower_componenents folder
some custom javascript in a different js folder
my concat task is the following:
concat: {
dist: {
src: [
'bower_components/jquery/jquery.js',
'bower_components/imagesloaded/imagesloaded.js',
'js/libs/*.js',
'js/custom/*.js'
],
dest: 'js/build/production.js'
}
}, //end concat
the result gets then processed by grunt uglifier like so:
uglify: {
dist: {
src: 'js/build/production.js',
dest: '_site/js/production.min.js'
}
}, //end uglify
what happens here is everything goes smoothly if i add just ONE library from bower_components folder (in my case jquery). if i add a second one (in my case images loaded), the resulting javascript file gets broken and no javascript works at all.
if i inspect the production.min.js file i notice all the needed code is actually there, but it doesn't work.
what am i missing?
should i use grunt-bower-concat? if yes, why and will it concatenate also my custom js?
for a reference, i'm using this grunt boilerplate: https://github.com/vlrprbttst/grunt-boilerplate-v2
thanks!!
that's fixed with:
concat: {
options: {
separator: ';',
},
dist: {
and
uglify: {
options: {
mangle: false
},
dist: {

Error when trying to use grunt-contrib-uglify: "src files were empty"

I have the following Gruntfile.js:
module.exports = function(grunt) {
var config = {
pkg: grunt.file.readJSON('package.json'),
/* Some other tasks... */
uglify: {
options: {
banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
},
def: {
files: {
'out/src.js': 'out/src.min.js'
}
}
}
};
grunt.initConfig(config);
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.registerTask('default', [/* <other-tasks>, */ 'uglify:def']);
};
Folder structure is as follows:
project
|
+-out (folder)
+-Gruntfile.js
Important: I run grunt from the project folder.
When running grunt, there is a task before uglify:def which is responsible for generating src.js into project/out.
When I run grunt I can see src.js being generated into project/out, but when Grunt runs uglisy:def I get the following error:
Running "uglify:def" (uglify) task.
Destination out/src.js not written because src files were empty.
No files created.
What am i doing wrong?
Log
When running with --verbose I get:
Running "uglify:def" (uglify) task
Verifying property uglify.def exists in config...OK
Files: [no src] -> out/src.js
Options: banner="/*! My Pack 2015-07-19 */\r\n", footer="", compress={"warnings":false}, mangle={}, beautify=false, report="
min", expression=false, maxLineLen=32000, ASCIIOnly=false, screwIE8=false, quoteStyle=0
>> Destination out/src.js not written because src files were empty.
>> No files created.
I've a configuration like the following, and it works fine for me.
// uglify javascript
uglify: {
dev: {
options: {
mangle: true
},
files: {
'js/dest.min.js': 'js/source.js'
}
}
},
Probably you confused the destination with the source. Try to switch them.
It were happening due to, you are not registering above given tasks.
OK, lets start with concatenation in grunt:
concat: {
css: {
src: ['./assets/css/*.css', './assets/css/**/*.css'],
dest: './dist/css/style.css'
},
js: {
src: ['./assets/js/*.js', './assets/js/**/*.js'],
dest: './dist/js/script.js'
}
},
so, this concat is supposed to collect all css files from above given url / directories and concatenate to given destination in one place and so with js.
this will be simple concatenated style.css and script.js at dest destination directory.
but it won't work, till you not register this concat task inside below line:
grunt.registerTask('default', ['concat', 'cssmin', 'uglify']);
So, till concat will not concatenate those files in dest directory, how the uglify will collect and work!
Conclusion: task won't get execute till you not mention them inside grunt.registerTask function.
My problem was that the path to my source file was incorrect. So it wasn't so much that the file is "empty" but that it can't be found.

Categories