-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
129 lines (109 loc) · 4.1 KB
/
index.js
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
124
125
126
127
128
129
/*! *
* Live - Connect Middleware
* Copyright(c) 2014 Paper & Equator, LLC
* Copyright(c) 2014 West Lane
* MIT Licensed
*/
var send = require("send")
, fs = require("fs")
, path = require("path")
, mime = require("mime")
, socket = require("socket.io")
, bind = require("./lib/bind");
exports = module.exports = function(root, options) {
// root required
if (!root) throw new Error('live() root path required');
options = options || {};
options.index = options.index || 'index.html';
options.search = options.search || /<\/body>/; // insert script here
// setup socket.io instance
var io = null;
function onChange(filename, targets) {
io.sockets.emit("refresh", {
filename: filename,
targets: targets
});
// allow custom onChange event
if (options.onChange && typeof(options.onChange) == "function") {
options.onChange.apply(this, arguments);
}
}
return function Watch(req, res, next) {
// create socket.io link for browser
if (!io) {
io = socket.listen(res.connection.server);
io.set("log level", 1);
}
var writeHead = res.writeHead
, write = res.write
, end = res.end
, content_type = null
, content_length = null
html_inject = ' <script src="/__refresh__.js"></script>\n';
// serve watcher client-side script
if (req.url == "/__refresh__.js") {
return send(req, "/refresh.js")
.root(__dirname + '/public')
.pipe(res);
}
// make sure we don't try to watch socket.io files
else if (req.url.match("/socket.io/")) {
return next();
}
//overload writeHead() to knock out any pre-defined content length
res.writeHead = function(statusCode, reasonPhrase, headers) {
if (content_type == "text/html") res.removeHeader("content-length");
writeHead.apply(res, arguments);
}
//overload write() to inject script in HTML
res.write = function(chunk, encoding){
if (content_type === null) {
if (res.getHeader("content-type")) {
content_type = res.getHeader("content-type")
.match(/[a-z]*\/[a-z]*/)[0];
}
}
if (content_type == "text/html") {
content_length += getSize(chunk);
var content = String(chunk);
if (content.match(options.search)) {
var new_content = content.replace(options.search, html_inject + '$&');
// transform chunk with script insert
chunk = Buffer(new_content, "utf8");
}
}
write.apply(res, arguments);
}
//overload end() to keep track of files to watch
res.end = function(chunk, encoding){
// pass through contents first
if (chunk) {
this.write(chunk, encoding);
}
end.call(res);
// now watch any requested URL or includes
// assume we're serving static files based on root
// also support connect-compile middleware
var watch = req.parts || [];
var main_file = path.resolve(root + req.url);
if (!req.url.match("\.[A-Za-z1-9]$")) {
// this could be a default view
// so make sure we don't try to watch the entire directory
main_file = path.normalize(main_file + "/" + options.index);
content_type = mime.lookup(main_file);
}
watch.push(main_file)
for (var idx in watch) {
if (fs.existsSync(watch[idx])) {
bind(root,watch[idx], req.url, content_type, onChange);
}
}
};
next();
}
}
function getSize(chunk) {
return Buffer.isBuffer(chunk)
? chunk.length
: Buffer.byteLength(chunk);
}