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() %>'
],
Related
I'm trying to concatenate and then babelify and uglify files with Grunt.
I'd like to read an external file list, from a file where the files are written one for each line, newline separated.
I'm trying to use the following GruntFile.js, but Grunt says (after I added the src=['<%= jsFiles.toString().split("\n") %>'] line):
Running "browserify:dist1" (browserify) task
Warning: An error occurred while processing a template (Invalid or unexpected token). Use --force to continue.
Where is the error?
This is the GruntFile.js
module.exports = function(grunt) {
grunt.initConfig({
jsFiles: grunt.file.read('scripts/s.list'),
env: {
prod: {
NODE_ENV: 'production'
}
},
browserify: {
dist1: {
options: {
transform: [
['babelify', {presets: ['es2015']}]
]
},
src: ['<%= jsFiles.toString().split("\n") %>'],
dest: '/WebContent/js/libs/s.bundle.js'
},
},
uglify: {
my_target1: {
files: {
'/WebContent/js/libs/s.bundleuglified.js': ['/WebContent/js/libs/s.bundle.js']
}
},
}
});
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-browserify');
grunt.loadNpmTasks('grunt-env');
grunt.registerTask('default', ['release']);
grunt.registerTask('release', ['env', 'browserify', 'uglify']);
};
Edit: I added a backslash to \n and the error has gone, but the babelify task gives me an empty file...
Edit2: I was able to read the file list using the following two lines at the beginning of the GruntFile.js
const jsFiles = grunt.file.read('scripts/s.list');
const jsFilesArray = jsFiles.toString().split("\n");
and then
src: jsFilesArray.slice(0, jsFilesArray.length-1),
because the last element was '' and it gave the error Warning: must provide pattern” as Beniamin H suggested.
Edit3: I found that the babelify task was reading the files in alphabetical order, so I had to first concat them, as explained here, and then babelify and uglify
You don't need to use any '<%= %>'. The file is read synchronously into jsFiles property and it can be used immediately. You may want to specify encoding for grunt.file.read to get a string: https://gruntjs.com/api/grunt.file#grunt.file.read
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: {
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
I'm having trouble configuring Grunt to watch my project files, rebuild and update a page hosted in a connect server. If I run any of the build tasks and then 'watch' as part of a combined task, then 'watch' seems to get stuck in a loop, endlessly printing the message.
Running "watch" task
Waiting...
Warning: must provide pattern
If instead I just run $ grunt watch, it will happily watch my source files and compile/build as appropriate.
I think the relevant task configurations are these:
watch: {
html: {
files: [ '<%= site.partials %>', '<%= site.layouts %>', '<%= site.pages %>' ],
tasks: [ 'html' ]
},
sass: {
files: [ '<%= site.src %>sass/*.scss' ],
tasks: [ 'styles' ]
}
},
// development server
connect: {
options: {
port: 8080,
livereload: 35729,
hostname: 'localhost',
},
dev: {
options: {
directory: 'build',
}
}
},
and the task definitions:
grunt.registerTask( 'build', [ 'styles', 'html', ] );
grunt.registerTask( 'default', [ 'build','connect:dev', 'watch' ] );
The 'styles' and 'html' tasks run grunt-sass and assemble. As stated above, running any of these tasks, or even 'watch' on its own yields the expected results. This suggests my config object has site.partials, site.dest etc defined correctly. The problem only happens when I run any task and then 'watch', as in the default task.
I just encountered a similar problem when I had been editing my Gruntfile and left a field (that should have had a file pattern) blank.
Check your Gruntfile for an empty file field.
In my specific example:
wiredep: {
options: {
overrides: {
"jquery-ui": {
"main": [
"jquery-ui.js",
"themes/base/jquery-ui.css",
""
]
}
}
}
}
Note the empty string above. That generated an error very similar to yours. It seems that Grunt doesn't tell you where the error is, unfortunately. You'll just need to scan through your Gruntfile manually to find the error.
connect:dev is the problem. Remove that and it should work fine.
I've just scaffolded an Angular app using Yeoman. I've noticed that the build task does several things by default, including minifying and concatenating js files.
I'd like to have a simpler build task that didn't do any minifying or concatenation, and, instead, only did the following two things:
compile my .scss into .css
copy a working app into my distribution directory
Can anyone help me write a grunt task that will do (only) these two things?
Many thanks.
Ok, I've edited the default grunt file so that it does what I want.
My solution involved writing tasks called copy:devDist and compass:devDist, and then combining them into a devDist task.
//
// copy:devDist --> copies everything into the dist folder, except styles/
//
copy: {
[...]
devDist: {
files: [{
expand: true,
dot: true,
cwd: '<%= yeoman.app %>',
dest: '<%= yeoman.dist %>',
src: [
'**','!styles/**' // everything but styles/
]
}]
}
},
//
// compass:devDist --> compile the sass; put result in dist/styles/
//
compass: {
[...]
devDist: {
options: {
cssDir: '<%= yeoman.dist %>/styles'
}
}
},
//
// register a 'devDist' task that calls the two tasks above
//
grunt.registerTask('devDist', [
'clean:dist',
'copy:devDist',
'compass:devDist'
]);
Now running grunt devDist compiles my css and puts a fully functional app into my dist folder. Excellent. :)