connect-livereload
Advanced tools
Comparing version 0.2.0 to 0.3.0
129
index.js
@@ -1,48 +0,89 @@ | ||
module.exports = function liveReload(opt) { | ||
module.exports = function livereload(opt) { | ||
// options | ||
var opt = opt || {}; | ||
var ignore = opt.ignore || opt.excludeList || ['.js', '.css', '.svg', '.ico', '.woff', '.png', '.jpg', '.jpeg']; | ||
var html = opt.html || _html; | ||
var rules = opt.rules || [{ | ||
match: /<\/body>/, | ||
fn: prepend | ||
}, { | ||
match: /<\/html>/, | ||
fn: prepend | ||
}, { | ||
match: /<\!DOCTYPE.+>/, | ||
fn: append | ||
}]; | ||
var port = opt.port || 35729; | ||
var excludeList = opt.excludeList || ['.woff', '.js', '.css', '.ico']; | ||
var src = opt.src || "' + (location.protocol || 'http:') + '//' + (location.hostname || 'localhost') + ':" + port + "/livereload.js?snipver=1"; | ||
var snippet = "\n<script type=\"text/javascript\">document.write('<script src=\"" + src + "\" type=\"text/javascript\"><\\/script>')</script>\n"; | ||
function getSnippet() { | ||
/*jshint quotmark:false */ | ||
var snippet = [ | ||
"<!-- livereload script -->", | ||
"<script type=\"text/javascript\">document.write('<script src=\"http://'", | ||
" + (location.host || 'localhost').split(':')[0]", | ||
" + ':" + port + "/livereload.js?snipver=1\" type=\"text/javascript\"><\\/script>')", | ||
"</script>", | ||
"" | ||
].join('\n'); | ||
return snippet; | ||
}; | ||
// helper functions | ||
var regex = (function() { | ||
var matches = rules.map(function(item) { | ||
return item.match.source; | ||
}).join('|'); | ||
function bodyExists(body) { | ||
return new RegExp(matches); | ||
})(); | ||
function prepend(w, s) { | ||
return s + w; | ||
} | ||
function append(w, s) { | ||
return w + s; | ||
} | ||
function _html(str) { | ||
if (!str) return false; | ||
return /<[:_-\w\s\!\/\=\"\']+>/i.test(str); | ||
} | ||
function exists(body) { | ||
if (!body) return false; | ||
return (~body.lastIndexOf("</body>")); | ||
return regex.test(body); | ||
} | ||
function snippetExists(body) { | ||
if (!body) return true; | ||
return (~body.lastIndexOf("/livereload.js?snipver=1")); | ||
function snip(body) { | ||
if (!body) return false; | ||
return (~body.lastIndexOf("/livereload.js")); | ||
} | ||
function acceptsHtmlExplicit(req) { | ||
var accept = req.headers["accept"]; | ||
if (!accept) return false; | ||
return (~accept.indexOf("html")); | ||
function snap(body) { | ||
var _body = body; | ||
rules.some(function(rule) { | ||
if (rule.match.test(body)) { | ||
_body = body.replace(rule.match, function(w) { | ||
return rule.fn(w, snippet); | ||
}); | ||
return true; | ||
} | ||
return false; | ||
}); | ||
return _body; | ||
} | ||
function isExcluded(req) { | ||
function accept(req) { | ||
var ha = req.headers["accept"]; | ||
if (!ha) return false; | ||
return (~ha.indexOf("html")); | ||
} | ||
function leave(req) { | ||
var url = req.url; | ||
var excluded = false; | ||
var ignored = false; | ||
if (!url) return true; | ||
excludeList.forEach(function(exclude) { | ||
if (~url.indexOf(exclude)) { | ||
excluded = true; | ||
ignore.forEach(function(item) { | ||
if (~url.indexOf(item)) { | ||
ignored = true; | ||
} | ||
}); | ||
return excluded; | ||
return ignored; | ||
} | ||
return function(req, res, next) { | ||
// middleware | ||
return function livereload(req, res, next) { | ||
if (res._livereload) return next(); | ||
res._livereload = true; | ||
var writeHead = res.writeHead; | ||
@@ -52,6 +93,12 @@ var write = res.write; | ||
if (!acceptsHtmlExplicit(req) || isExcluded(req)) { | ||
if (!accept(req) || leave(req)) { | ||
return next(); | ||
} | ||
function restore() { | ||
res.writeHead = writeHead; | ||
res.write = write; | ||
res.end = end; | ||
} | ||
res.push = function(chunk) { | ||
@@ -62,12 +109,13 @@ res.data = (res.data || '') + chunk; | ||
res.inject = res.write = function(string, encoding) { | ||
res.write = write; | ||
if (string !== undefined) { | ||
var body = string instanceof Buffer ? string.toString(encoding) : string; | ||
if ((bodyExists(body) || bodyExists(res.data)) && !snippetExists(body) && (!res.data || !snippetExists(res.data))) { | ||
res.push(body.replace(/<\/body>/, function(w) { | ||
return getSnippet() + w; | ||
})); | ||
if (exists(body) && !snip(res.data)) { | ||
res.push(snap(body)); | ||
return true; | ||
} else if (html(body) || html(res.data)) { | ||
res.push(body); | ||
return true; | ||
} else { | ||
return res.write(string, encoding); | ||
restore(); | ||
return write.call(res, string, encoding); | ||
} | ||
@@ -78,7 +126,8 @@ } | ||
res.writeHead = function() {}; | ||
res.end = function(string, encoding) { | ||
res.writeHead = writeHead; | ||
res.end = end; | ||
restore(); | ||
var result = res.inject(string, encoding); | ||
if (!result) return res.end(string, encoding); | ||
if (!result) return end.call(res, string, encoding); | ||
if (res.data !== undefined && !res._header) res.setHeader('content-length', Buffer.byteLength(res.data, encoding)); | ||
@@ -85,0 +134,0 @@ res.end(res.data, encoding); |
{ | ||
"name": "connect-livereload", | ||
"description": "connect middleware for adding the livereload script to the response", | ||
"version": "0.2.0", | ||
"version": "0.3.0", | ||
"author": "Andi Neck <andi.neck@intesso.com>", | ||
@@ -6,0 +6,0 @@ "contributors": [ |
107
README.md
@@ -8,3 +8,3 @@ connect-livereload | ||
[](https://travis-ci.org/intesso/connect-livereload) | ||
[](http://badge.fury.io/js/connect-livereload) | ||
install | ||
@@ -18,12 +18,16 @@ ======= | ||
=== | ||
this middleware can be used with a LiveReload server e.g. [grunt-reload](https://github.com/webxl/grunt-reload). | ||
note: if you use this middleware, you should make sure to switch off the Browser LiveReload Extension if you have it installed. | ||
In your connect or express application add this after the static and before the dynamic routes: | ||
this middleware can be used with a LiveReload server e.g. [grunt-reload](https://github.com/webxl/grunt-reload) or [grunt-contrib-watch](https://github.com/gruntjs/grunt-contrib-watch). | ||
`connect-livereload` itself does not serve the `livereload.js` script. | ||
In your connect or express application add this after the static and before the dynamic routes. | ||
If you need liveReload on static html files, then place it before the static routes. | ||
`ignore` gives you the possibility to ignore certain files or url's from being handled by `connect-livereload`. | ||
## connect/express example | ||
```javascript | ||
var liveReloadPort = 35729; | ||
var excludeList = ['.woff', '.flv']; | ||
app.use(require('connect-livereload')({ | ||
port: liveReloadPort, | ||
excludeList: excludeList | ||
port: 35729 | ||
})); | ||
@@ -34,7 +38,84 @@ ``` | ||
###note | ||
if you add this middleware before the static middleware, it will lead to problems. | ||
If you can't avoid that for some reason, you have to add all of the static file extensions to the `excludeList: ['.css', '.js', '.ico', '.png', 'ect...']` | ||
## options | ||
Options are not mandatory: `app.use(require('connect-livereload')());` | ||
The Options have to be provided when the middleware is loaded: | ||
e.g.: | ||
``` | ||
app.use(require('connect-livereload')({ | ||
port: 35729, | ||
ignore: ['.js', '.svg'] | ||
})); | ||
``` | ||
These are the available options with the following defaults: | ||
```javascript | ||
// these files will be ignored | ||
ignore: ['.js', '.css', '.svg', '.ico', '.woff', '.png', '.jpg', '.jpeg'], | ||
// this function is used to determine if the content of `res.write` or `res.end` is html. | ||
html: function (str) { | ||
return /<[:_-\w\s\!\/\=\"\']+>/i.test(str); | ||
}, | ||
// rules are provided to find the place where the snippet should be inserted. | ||
// the main problem is that on the server side it can be tricky to determine if a string will be valid html on the client. | ||
// the function `fn` of the first `match` is executed like this `body.replace(rule.match, rule.fn);` | ||
// the function `fn` has got the arguments `fn(w, s)` where `w` is the matches string and `s` is the snippet. | ||
rules: [{ | ||
match: /<\/body>/, | ||
fn: prepend | ||
}, { | ||
match: /<\/html>/, | ||
fn: prepend | ||
}, { | ||
match: /<\!DOCTYPE.+>/, | ||
fn: append | ||
}], | ||
// port where the script is loaded | ||
port: 35729, | ||
// location where the script is provided (not by connect-livereload). Change this e.g. when serving livereload with a proxy. | ||
src: "http://localhost:35729/livereload.js?snipver=1", | ||
``` | ||
please see the [examples](https://github.com/intesso/connect-livereload/tree/master/examples) for the app and Grunt configuration. | ||
## grunt example | ||
The following example is from an actual Gruntfile that uses [grunt-contrib-connect](https://github.com/gruntjs/grunt-contrib-connect) | ||
```javascript | ||
connect: { | ||
options: { | ||
port: 3000, | ||
hostname: 'localhost' | ||
}, | ||
dev: { | ||
options: { | ||
middleware: function (connect) { | ||
return [ | ||
require('connect-livereload')(), // <--- here | ||
checkForDownload, | ||
mountFolder(connect, '.tmp'), | ||
mountFolder(connect, 'app') | ||
]; | ||
} | ||
} | ||
} | ||
} | ||
``` | ||
For use as middleware in grunt simply add the following to the **top** of your array of middleware. | ||
```javascript | ||
require('connect-livereload')(), | ||
``` | ||
You can pass in options to this call if you do not want the defaults. | ||
`dev` is simply the name of the server being used with the task `grunt connect:dev`. The other items in the `middleware` array are all functions that either are of the form `function (req, res, next)` like `checkForDownload` or return that like `mountFolder(connect, 'something')`. | ||
alternative | ||
@@ -52,3 +133,3 @@ =========== | ||
===== | ||
run the tests with | ||
run the tests with | ||
``` | ||
@@ -55,0 +136,0 @@ mocha |
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Non-existent author
Supply chain riskThe package was published by an npm account that no longer exists.
Found 1 instance in 1 package
9826
116
138
0
1