124 lines
3.3 KiB
JavaScript
124 lines
3.3 KiB
JavaScript
|
|
var fs = require('fs');
|
|
var Server = require('..').Server;
|
|
|
|
// Basic grunt facade to tiny-lr server.
|
|
//
|
|
// XXX: Consider
|
|
//
|
|
// - spawning the server in the background.
|
|
// - changing the reload target to use HTTP requests to notify the server.
|
|
// - providing a `tinylr-stop` task.
|
|
//
|
|
// Examples
|
|
//
|
|
// grunt tinylr-start &
|
|
// grunt tinylr-reload:path/to/asset.ext[,...]
|
|
//
|
|
|
|
module.exports = function(grunt) {
|
|
var util = grunt.util || grunt.utils;
|
|
var _ = util._;
|
|
|
|
// server instance
|
|
var server;
|
|
|
|
// Task to start up a new tiny-lr Server, with the provided port.
|
|
//
|
|
// - options - Hash of options in Gruntfile `tiny-lr` prop with the following
|
|
// properties
|
|
// :port - The port to listen on (defaults: 35729)
|
|
//
|
|
grunt.registerTask('tinylr-start', 'Start the tiny livereload server', function() {
|
|
var options = _.defaults(grunt.config('tiny-lr') || {}, {
|
|
port: 35729
|
|
});
|
|
|
|
// if grunt 0.3, build up the list of mtimes to compare
|
|
changed();
|
|
|
|
var done = this.async();
|
|
server = new Server();
|
|
grunt.log.writeln('... Starting server on ' + options.port + ' ...');
|
|
server.listen(options.port, this.async());
|
|
});
|
|
|
|
// Task to send a reload notification to the previously started server.
|
|
//
|
|
// This should be configured as a "watch" task in your Gruntfile, and run
|
|
// after tinylr-start.
|
|
//
|
|
// Example
|
|
//
|
|
// watch: {
|
|
// reload: {
|
|
// files: ['**/*.html', '**/*.js', '**/*.css', '**/*.{png,jpg}'],
|
|
// tasks: 'tinylr-reload'
|
|
// }
|
|
// }
|
|
//
|
|
grunt.registerTask('tinylr-reload', 'Sends a reload notification to the livereload server, based on `watchFiles.changed`', function() {
|
|
if(!server) return;
|
|
var files = changed();
|
|
grunt.log.verbose.writeln('... Reloading ' + grunt.log.wordlist(files) + ' ...');
|
|
server.changed({
|
|
body: {
|
|
files: files
|
|
}
|
|
});
|
|
});
|
|
|
|
// Helpers
|
|
|
|
// This normalize the list of changed files between 0.4 and 0.3. If
|
|
// `watchFiles` is available, then use that.
|
|
//
|
|
// Otherwise, go through each watch config with `reload` as part of their
|
|
// `tasks`, concat all the files, and maintain a list of mtime. A changed
|
|
// files is simply a file with a "newer" mtime.
|
|
function changed() {
|
|
if(grunt.file.watchFiles) return grunt.file.watchFiles.changed;
|
|
|
|
var watch = grunt.config('watch');
|
|
|
|
var files = Object.keys(watch).filter(function(target) {
|
|
var tasks = watch[target].tasks;
|
|
if(!tasks) return false;
|
|
return ~tasks.indexOf('reload');
|
|
}).reduce(function(list, target) {
|
|
return list.concat(watch[target].files || []);
|
|
}, []);
|
|
|
|
files = grunt.file.expandFiles(files).filter(ignore('node_modules'));
|
|
|
|
// stat compare
|
|
var stats = changed.stats = changed.stats || {};
|
|
|
|
var current = files.map(function(filepath) {
|
|
var stat = fs.statSync(filepath);
|
|
stat.file = filepath;
|
|
return stat;
|
|
}).reduce(function(o, stat) {
|
|
o[stat.file] = stat.mtime.getTime();
|
|
return o;
|
|
}, {});
|
|
|
|
|
|
files = Object.keys(current).filter(function(file) {
|
|
if(!stats[file]) return true;
|
|
return stats[file] !== current[file];
|
|
});
|
|
|
|
|
|
changed.stats = current;
|
|
return files;
|
|
}
|
|
|
|
|
|
// filter helper
|
|
function ignore(pattern) { return function(item) {
|
|
return !~item.indexOf(pattern);
|
|
}}
|
|
|
|
};
|