Grunt livecompiling less using watch - gruntjs

I know there are some quite similar questions, but I can't get it to work.
I'm using grunt, including connect, less and watch. Everything works, except for the livecompiling of the .css with less and watch. Like this, I always have to restart grunt etc.
This is my code:
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
connect: {
server: {
options: {
port: 8000,
hostname: 'localhost',
base: 'public',
keepalive: true
}
}
},
less: {
development: {
options: {
compress: true,
yuicompress: true,
optimization: 2
},
files: {
"public/style/style.css": "public/style/main.less"
}
}
},
watch: {
files: ['**/*'],
tasks: ['less', 'connect'],
styles: {
files: ['public/style/main.less'], //which files to watch
tasks: ['less'],
options: {
livereload: true
}
}
}
});
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.registerTask('default', ['less','connect','watch']);
};
Please let me know if more information is needed.

You have to add the livereload snippet in your html file to get it works:
<script>
document.write('<script src="http://' + (location.host || 'localhost').split(':')[0] + ':35729/livereload.js?snipver=1"><\/script>')
</script>
35729 is the port of your livereload server.
To further information see the documentation. Also you should read how to enable livereload in your html.

In addition to Mario's answer, I tried around a little.
I found the solution like this:
I ran watch alone, without less or connect and I noticed that it left something in the console, which I did not see in the console when I had it running in combination with connect and less. Next thing I noticed was the "Waiting forever..." in connect's entry in the console. Like this, nothing happenend, because it waited forever. The consequence of this was that watch could not be executed. That also explains why I never watch's entry in the console.
So the solution was this:
I had to delete "keepalive:true" from connect in the Gruntfile.

Related

grunt-sync with grunt-contrib-watch

I am currently trying to configure grunt-sync to run inside a watch and am running into issues. I've reported the issue to the module's github page but decided to post here to draw upon the general development population rather than wait for a single contributor to come across my issue report.
So, I'm thinking this may just be a gap in my understanding of how to drive grunt tasks through a watch. I've got watches up and running for several tasks already and I'm adding grunt-sync to my workflow to automate publication of my changes to a network directory that blah blah blah...not important; my watch is working for some stuff but not for this. I'm dropping in the relevant config section along with my "concurrent","karma", and "sass" tasks to give you the gist of my overall grunt config.
module.exports = function(grunt){
grunt.initConfig({
pkg: grunt.file.readJSON("package.json"),
project: {
app: 'app',
},
sync:{
main: {
files:
[
{
cwd: 'app/',
src: [
'**/*.js',
'**/*.html',
'**/*.css',
'!app/node_modules/**'
],
dest: ['publish/']
}
],
verbose: true
}
},
karma: {
unit: {
configFile: 'test/karma.conf.js'
},
continuous:{
configFile: 'test/karma.conf.js',
singleRun: true,
browsers: ['PhantomJS']
}
},
sass:{
dev: {
options:{
style: 'expanded',
compass: false
},
files:{
'app/css/app.css':'app/css/app.scss'
}
},
dist: {
options: {
style: 'compressed',
compass: false
},
files:{
'app/css/app.css':'app/css/app.scss'
}
}
},
watch: {
sass: {
files: 'app/css/**/{,*/}*.{scss,sass}',
tasks: ['sass:dev']
},
styles: {
files: ['app/css/app.css'],
tasks: ['autoprefixer']
},
// karma: {
// files: ['test/*.js',
// 'test/**/*.js'
// ],
// tasks: ['karma:unit:run']
// },
livereload:{
options: {livereload: true},
files: ['app/**/*'],
},
sync:{
files: ['app/**'],
tasks: ['sync:main']
}
},
concurrent:
{
target: {
tasks: [
'karma:unit',
'watch'
],
options: {
logConcurrentOutput: true
}
}
}
});
require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);
grunt.registerTask('default', [
'sass:dev',
'concurrent:target'
]
);
};
Currently receiving the following warning when I grunt
Warning: Task "sync:main" not found. Use --force to continue.
Aborted due to warnings.
Since there is only the main subtask, I thought that maybe changing the watch from executing ['sync:main'] to executing ['sync'] would possibly work. The warning goes away but poof nothing happens...so I'm not sure if the issue is with my config or with the module implementation.
Any ideas?
Edit to Add:
From the module's github site, I see the following in sync.json
{
"main": {
"files": [{
"src": ["**"],
"dest": "bin/to",
"cwd": "bin/from"
}]
}
}
so that would lead me to believe that "main" is the name I should be using for the sync subtask. I'm really confused as to why grunt isn't recognizing it in my config, but I am not too terribly familiar with dissecting the code for grunt modules.
Well...turns out I referenced a module in my gruntfile before I ran npm install on it and then decided to come on the internet to tell everybody about it.
Edit:
To partially exonerate myself, I found the console that I used to run npm install grunt-sync --save-dev. I had run it, but I was in the
wrong directory; it added it to the wrong gruntfile.
To answer my own question, the gruntfile packaged with the [grunt-sync] module contains a watch section, so you just have to have grunt-contrib-watch installed; you don't have to do anything special. And that makes sense. A folder synchronization task would be pretty darned worthless without a file system watch, so it is perfectly reasonable to run the task in a very broad watch but with an inherent blacklist (it watches all files in all folders but only operates on files matching a src pattern.
So to get it to syn-down all files on all file changes,
sync: {
main:{
files:[{
src:[
'**'
]
, dest: 'publish'
}
]
,verbose: true
}
},
will copy all files to the publish subdirectory. I run mine inside a concurrent task
concurrent:
{
target: {
tasks: [
'karma:unit',
'sync:main',
'watch'
],
options: {
logConcurrentOutput: true
}
}
}
Personally, I'll probably be swapping this out with grunt-rsync because grunt-sync simply performs the file copy task inside [sync:main] What I want it to do is to only send deltas to the publish folder every time I save a file; that's a task for rsync.

Need to Perform a Grunt Watch Forever

I'm new to Node.js and Grunt... I'm attempting to use Node.js and Grunt on a Windows server to watch my main.less file and do a standard compile and concatinate. I'm able to do this while the command prompt is open, but I need this to run as a daemon while not logged into the server since the .less files get deployed from our CMS that sits in the cloud.
I found promising documentation in Grunt-Forever, but it requires you to point to an application, while I just want to perform the grunt watch task.
Someone else asked a similar question 9 months ago, but nobody gave an answer:
Grunt.js Watch Forever
I tried this from the command line:
FWIW, you can do forever /usr/local/bin/grunt --base . watch to use forever with grunt watch atm.
But, I got errors.
Here is my gruntfile:
module.exports = function(grunt) {
grunt.registerTask('watch', [ 'watch' ]);
grunt.initConfig({
concat: {
js: {
src: [
'js/global.js','js/googlemap.js'
],
dest: 'js/main.min.js'
},
},
uglify: {
options: {
mangle: false
},
js: {
files: {
'js/main.min.js': ['js/main.min.js']
}
}
},
less: {
style: {
files: {
"css/style.css": "less/main.less"
}
}
},
watch: {
js: {
files: ['js/global.js','js/googlemap.js'],
tasks: ['concat:js', 'uglify:js']
},
css: {
files: ['less/*.less'],
tasks: ['less:style']
}
}
});
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-contrib-watch');
};
Any help is much appreciated!
Use node to call grunt, use PM2 to run and manage node.
Try running the grunt watch task with nohup. Since you mentioned "Windows server" you can check this answer about nohup equivalent in Windows. Then you will have the grunt task running even when you log out of the server.

Are there global variables in grunt?

While trying to do some kind of generic grunt task i got stuck while accessing variables/options.
I need some kind of global variable or something similar.
It seems I have overlooked something.
If I run grunt sassCompile:myprojectFolder, everything works fine
while grunt sassWatch:myprojectFolder does not.
I run it in verbose mode and it seems projectPath is empty while compass is being called by watch.
compass options (from verbose output):
sassCompile: config="projectRoot/myprojectFolder/config.rb" ...
sassWatch: config="config.rb" ...
This is the Gruntfile.js is used for testing:
What I am doing wrong?
(function() {
'use strict';
module.exports = function (grunt) {
grunt.initConfig({
compass: {
dev: {
options: {
config: "<%= projectPath %>config.rb",
basePath: "<%= projectPath %>",
specify: ["<%= projectPath %>src/sass/style*.scss","!**/*ie*.scss"],
bundleExec: true
}
}
},
watch: {
css: {
files: ['<%= projectPath %>../**/*.scss'],
tasks: ['compass']
}
}
});
grunt.registerTask('sassCompile', 'compass', function (project) {
grunt.config('projectPath', 'projectRoot/' + project + '/');
grunt.task.run('compass');
});
grunt.registerTask('sassWatch', 'watch', function (project) {
grunt.config('projectPath', 'projectRoot/' + project + '/');
grunt.task.run('watch');
});
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-compass');
};
}());
This is definitely an interesting approach you have there – it took me a while to understand what is going on.
What happens when run grunt sassWatch:myprojectFolder is that the watch task gets started with the projectPath you supplied after the colon, but, when watch detects a change it runs the compass task without the configuration.
That is because grunt-contrib-watch runs it's tasks by starting a new grunt process. You could run the tasks inside the same process by using options: { spawn: false }, but that seems to be discouraged.
I would suggest you try this:
watch: {
css: {
files: ['<%= projectPath %>../**/*.scss'],
tasks: ['sassCompile:<%= projectPath %>']
}
}
That way watch will run sassCompile:myprojectFolder in the spawned grunt process, making sure the configuration gets transferred to the compass task.
At the grunt page there is a section about global variables, but they won't work across multiple processes.
It would be possible to start a new async process by hand and handover the needed variables.
You could take a look at here and possible extend it to accept parameters for the new processes.

Grunt - lint only modified files using grunt-newer

I'm running a Grunt task that uses Concurrent to run both Nodemon and Watch/Livereload. On default load, I lint and launch Concurrent. I would also like to set up a Watch to lint individual files on change. Currently, all files are linted when any one file is changed.
I have examined a similar question on StackOverflow and decided to go with grunt-newer as a potential solution. In my implementation below, however, the 'newer' prefix doesn't seem to do anything. How can I fix this so that only changed files are linted?
module.exports = function(grunt) {
//load all dependencies
require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
concurrent: {
dev: {
options: {
logConcurrentOutput: true
},
tasks: ['watch', 'nodemon']
}
},
jshint: {
files: ['Gruntfile.js', 'client/src/*.js', 'server/**/*.js'],
options: {
'-W030': true,
'-W083': true,
globals: {
console: true,
module: true,
document: true
}
}
},
watch: {
all: {
files: ['<%= jshint.files %>'],
tasks: ['newer:jshint']
},
frontend: {
files: ['client/**/*.{css,js,html}'],
options: {
livereload: true
}
}
},
nodemon: {
dev: {
options: {
file: 'server/server.js',
watchedFolders: ['server']
}
}
}
});
grunt.registerTask('test', ['jshint']);
grunt.registerTask('default', ['jshint', 'concurrent']);
};
I was having the same problem and finally figured it out. The solution is hidden deep in the documentation and very misleading with the spawn option in the code sample: https://github.com/gruntjs/grunt-contrib-watch#compiling-files-as-needed
Your config file should remain the same as you have it in your question, but you need to add a listener to the watch event. I recommend the 'robust' option they provide (modified for you specific task config). Place this code just above the call to grunt.initConfig and after you require calls.
var changedFiles = Object.create(null);
var onChange = grunt.util._.debounce(function() {
// Modified to point to jshint.files as per the task example in the question.
grunt.config('jshint.files', Object.keys(changedFiles));
changedFiles = Object.create(null);
}, 200);
grunt.event.on('watch', function(action, filepath) {
changedFiles[filepath] = action;
onChange();
});
Add the nospawn option to the all watch task. This is what is misleading in in the documentation. It mentions it should be disabled if you want dynamically modify your config but basically prevents it from working with newer unless it's set to true:
watch: {
all: {
files: ['<%= jshint.files %>'],
tasks: ['newer:jshint'],
options: {
nospawn: true,
}
},
...
NOTE: If you modify your grunt file while it's running then it will lint all files, not sure why it does this but then it gets stuck and will just keep linting everything for all changes you make. I just took out the 'gruntfile.js' from the list of files that should be linted to avoid it.

grunt: watch command never runs when including other tasks in registerTask method

I'm having some unexpected behavior with my Gruntfile. I've registered a task that looks like this: grunt.registerTask('dev', ['jekyll:server', 'watch:jekyll']) with the hopes that it will sequentially start a jekyll server, and then watch my project for specific file changes (using the grunt-contrib-watch plugin). Once it detects those changes, it would re-run jekyll:server automatically.
The problem I'm having is that when I run grunt dev, it will start the Jekyll server, but it will not run the watch commands. However, if I remove the server task from grunt dev, it will run the watch command as expected.
Below is the contents of my Gruntfile. Can anyone help me understand what is happening?
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
jekyll: {
server : {
server: true,
server_port: 4000,
exclude: ['node_modules']
},
prod: {
dest: './_site-release'
}
},
watch: {
jekyll: {
files: ['_posts/**/*.md', '_layout/*.html', '_includes/*.html', 'index.html'],
tasks: ['jekyll:server']
}
}
});
grunt.loadNpmTasks('grunt-jekyll');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.registerTask('default', 'jekyll:server');
grunt.registerTask('dev', ['jekyll:server', 'watch:jekyll']);
grunt.registerTask('release', 'jekyll:prod');
};
The server option makes the task block since it's persistent. You can either use the tasks watch option or something like grunt-concurrent to run jekyll and watch concurrently:
grunt.initConfig({
concurrent: {
target: {
tasks: ['jekyll:server', 'watch'],
options: {
logConcurrentOutput: true
}
}
}
});
grunt.loadNpmTasks('grunt-concurrent');
grunt.registerTask('default', ['concurrent:target']);

Resources