tiny-lr.js
3.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
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);
}}
};