1 | var Tinylr = require('tiny-lr')
|
2 | var unyield = require('unyield')
|
3 | var chokidar = require('chokidar')
|
4 |
|
5 | var debounce = require('./debounce')
|
6 | var hashFiles = require('./hashfile').hashFiles
|
7 | var isAsset = require('./helpers').isAsset
|
8 | var diffHashes = require('./helpers').diffHashes
|
9 | var filterFiles = require('./helpers').filterFiles
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 | exports.spawnLR = unyield(function * (port) {
|
17 | var lrServer = new Tinylr()
|
18 | lrServer.listen(port)
|
19 | return lrServer
|
20 | })
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 | exports.watchLR = function (root, lrServer, onChange) {
|
27 | var hashes = {}
|
28 |
|
29 | var update = unyield(function * (argsList) {
|
30 |
|
31 |
|
32 | var paths = argsList.reduce(function (list, args) {
|
33 | var fname = args[1]
|
34 | if (!isAsset(fname)) return list
|
35 |
|
36 | if (args[0] === 'delete') {
|
37 | delete hashes[fname]
|
38 | } else {
|
39 | list.push(fname)
|
40 | }
|
41 | return list
|
42 | }, [])
|
43 |
|
44 |
|
45 | paths = yield filterFiles(root, paths)
|
46 | if (paths.length === 0) return
|
47 |
|
48 |
|
49 | var newHashes = yield hashFiles(root, paths)
|
50 |
|
51 |
|
52 | var files = diffHashes(hashes, newHashes)
|
53 | if (files.length === 0) return
|
54 |
|
55 |
|
56 | if (onChange) onChange(files)
|
57 |
|
58 | files = files.map(escape)
|
59 | lrServer.changed({
|
60 | body: { files: files }
|
61 | })
|
62 | })
|
63 |
|
64 | var uupdate = function (argsList) {
|
65 | update(argsList, function (err) { if (err) throw err })
|
66 | }
|
67 |
|
68 | return chokidar.watch(root, {
|
69 | ignoreInitial: true,
|
70 | cwd: root
|
71 | })
|
72 | .on('all', debounce(uupdate, 50))
|
73 | }
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 | exports.injectLR = function (port) {
|
81 | var snippet = getSnippet(port)
|
82 |
|
83 | return function injectLR (req, res, next) {
|
84 | var write = res.write
|
85 | res.write = function (string, encoding) {
|
86 | if (!isHtmlResponse(res)) return write.call(res, string, encoding)
|
87 |
|
88 | var body = string instanceof Buffer ? string.toString() : string
|
89 | if (~body.indexOf('</body>')) {
|
90 | body = body.replace(/<\/body>/, function (w) {
|
91 | return snippet + w
|
92 | })
|
93 | } else {
|
94 | body += snippet
|
95 | }
|
96 | if (string instanceof Buffer) {
|
97 | string = new Buffer(body)
|
98 | } else {
|
99 | string = body
|
100 | }
|
101 | if (!this.headersSent) {
|
102 | this.setHeader('content-length', Buffer.byteLength(body))
|
103 | this._implicitHeader()
|
104 | }
|
105 | write.call(res, string, encoding)
|
106 | }
|
107 | next()
|
108 | }
|
109 | }
|
110 |
|
111 |
|
112 |
|
113 |
|
114 |
|
115 | function isHtmlResponse (res) {
|
116 | return res._headers &&
|
117 | res._headers['content-type'] &&
|
118 | res._headers['content-type'].indexOf('text/html') > -1
|
119 | }
|
120 |
|
121 |
|
122 |
|
123 |
|
124 |
|
125 | function getSnippet (port) {
|
126 | return [
|
127 | '<!-- livereload -->',
|
128 | "<script>document.write('<script src=\"http://'",
|
129 | "+(location.host||'localhost').split(':')[0]",
|
130 | "+':" + port + "/livereload.js?snipver=1\"><\\/script>')",
|
131 | '</script>'
|
132 | ].join('') + '\n'
|
133 | }
|
134 |
|
135 | exports.getSnippet = getSnippet
|