Permalink
Browse files

add live reload

  • Loading branch information...
1 parent 2c78f08 commit f8e953b19d67d81f981ee4a7b0f5db286b97c29e @marty-wang committed Nov 7, 2011
View
@@ -6,7 +6,8 @@ NServe is a nodejs-powered static file server that is created to facilitate loca
* Easy and Fast. One command and serve away.
* Allow user-defined transfer rate to mimck the real situations.
-* Delay cross-domain mock web services, including GET and POST.
+* Delay cross-domain mock web services, including GET and POST.
+* Live reload HTML/CSS/JS files. No need to manually refersh browsers.
* More to come...
# Installation
@@ -33,6 +34,7 @@ Options:
-d, --directory <root> specify the root directory, relative or absolute [current directory]
-w, --webservice-folder <folder name> specify the web service folder name ["ws"]
-D, --webservice-delay <n> specify the delay of the web service in millisecond [0]
+ -l, --live-reload automatically reload HTML/CSS/JS files
and open [http://localhost:3000](http://localhost:3000) in your browser.
@@ -22,15 +22,25 @@
try {
stat = fs.statSync(path);
return fs.readFile(path, function(err, data) {
- var contentType;
+ var contentType, size;
if (err == null) {
- _callback("start", path);
contentType = mime.lookup(path);
+ _callback("start", {
+ request: req,
+ path: path,
+ content: data,
+ contentType: contentType
+ });
+ size = stat.size;
+ if (req.modifiedData != null) {
+ data = req.modifiedData;
+ size = req.modifiedDataSize;
+ }
res.writeHead(200, {
'Content-Type': contentType
});
if (_rate != null) {
- return trans.transferData(data, stat.size, function(result) {
+ return trans.transferData(data, size, function(result) {
switch (result.status) {
case "transfer":
return res.write(result.payload);
@@ -64,7 +74,13 @@
_fn = fn;
_callback("init", _rate);
return function(req, res, next) {
- return _transfer(req, res, next, fn);
+ switch (req.method.toUpperCase()) {
+ case "GET":
+ case "POST":
+ return _transfer(req, res, next, fn);
+ default:
+ return next();
+ }
};
};
exports.transfer = transfer;
@@ -0,0 +1,62 @@
+(function() {
+ var cUtils, colors, fs, insertLiveScript, live, mime, parse, path, util, _isEnabled, _liveScript, _types;
+ fs = require("fs");
+ parse = require("url").parse;
+ path = require("path");
+ mime = require('mime');
+ cUtils = (require("connect")).utils;
+ colors = require("colors");
+ util = require("./util");
+ try {
+ _liveScript = fs.readFileSync(path.resolve(__dirname, "../public/live.js"), "utf8");
+ } catch (error) {
+ _liveScript = null;
+ console.error("[".grey + "failed".red + "]".grey + " to load live.js");
+ }
+ _types = ['text/html', 'text/css', 'application/javascript'];
+ _isEnabled = false;
+ live = function(root, enabled) {
+ _isEnabled = enabled;
+ return function(req, res, next) {
+ var contentType, filepath;
+ if (!_isEnabled) {
+ return next();
+ }
+ switch (req.method.toUpperCase()) {
+ case "HEAD":
+ filepath = root + parse(req.url).pathname;
+ contentType = mime.lookup(filepath);
+ if (_types.indexOf(contentType >= 0)) {
+ return fs.stat(filepath, function(err, stats) {
+ if (err == null) {
+ res.writeHead(200, {
+ 'Content-Type': contentType,
+ 'Etag': cUtils.etag(stats)
+ });
+ }
+ return res.end();
+ });
+ } else {
+ return next();
+ }
+ break;
+ default:
+ return next();
+ }
+ };
+ };
+ insertLiveScript = function(content, contentType) {
+ var html, idx;
+ if (!_isEnabled) {
+ return content;
+ }
+ if ((_liveScript != null) && contentType === "text/html") {
+ html = content.toString('utf8');
+ idx = html.lastIndexOf("</body>");
+ content = util.strSplice(html, idx, 0, '<script type="text/javascript">' + _liveScript + '</script>');
+ }
+ return content;
+ };
+ exports.live = live;
+ exports.insertLiveScript = insertLiveScript;
+}).call(this);
View
@@ -1,5 +1,5 @@
(function() {
- var DEFAULT_PORT, DEFAULT_WEBSERVICE_DELAY, DEFAULT_WEBSERVICE_FOLDER, colors, connect, fileTransfer, fs, http, parse, path, program, start, sys, util, webservice, _fileTransferCallback, _init, _isVerbose, _now, _parseCLI, _port, _rate, _root, _router, _server, _version, _versionNumber, _webserviceDelay, _webserviceFolder;
+ var DEFAULT_PORT, DEFAULT_WEBSERVICE_DELAY, DEFAULT_WEBSERVICE_FOLDER, colors, connect, fileTransfer, fs, http, livepage, parse, path, program, start, sys, util, webservice, _fileTransferCallback, _init, _isLiveReload, _isVerbose, _now, _parseCLI, _port, _rate, _root, _router, _server, _version, _versionNumber, _webserviceDelay, _webserviceFolder;
DEFAULT_PORT = 3000;
DEFAULT_WEBSERVICE_FOLDER = "ws";
DEFAULT_WEBSERVICE_DELAY = 0;
@@ -13,6 +13,7 @@
colors = require("colors");
fileTransfer = (require("./connect-file-transfer")).transfer;
webservice = (require("./connect-webservice")).webservice;
+ livepage = require('./connect-livepage');
util = require("./util");
/* Private */
_server = null;
@@ -23,6 +24,7 @@
_root = null;
_webserviceFolder = null;
_webserviceDelay = 0;
+ _isLiveReload = false;
_version = function() {
try {
return _versionNumber = util.getVersionNumber();
@@ -32,7 +34,7 @@
};
_parseCLI = function() {
var port, root, wsDelay, wsFolder;
- program.version(_versionNumber).option('-p, --port <n>', 'specify the port number [3000]', parseInt).option('-r, --rate <bit rate>', 'specify the file transfer rate in Bps, e.g. 100K or 5M').option('-v, --verbose', 'enter verbose mode').option('-d, --directory <root>', 'specify the root directory, either relative or absolute [current directory]').option('-w, --webservice-folder <folder name>', 'specify the webservice folder name ["ws"]').option('-D, --webservice-delay <n>', 'specify the delay of the web service in millisecond [0]', parseInt).parse(process.argv);
+ program.version(_versionNumber).option('-p, --port <n>', 'specify the port number [3000]', parseInt).option('-r, --rate <bit rate>', 'specify the file transfer rate in Bps, e.g. 100K or 5M').option('-v, --verbose', 'enter verbose mode').option('-d, --directory <root>', 'specify the root directory, either relative or absolute [current directory]').option('-w, --webservice-folder <folder name>', 'specify the webservice folder name ["ws"]').option('-D, --webservice-delay <n>', 'specify the delay of the web service in millisecond [0]', parseInt).option('-l, --live-reload', 'automatically reload HTML/CSS/JS files').parse(process.argv);
port = program.port;
if ((port != null) && !isNaN(port)) {
_port = port;
@@ -44,7 +46,8 @@
wsFolder = program.webserviceFolder;
_webserviceFolder = wsFolder != null ? util.normalizeFolderName(wsFolder) : DEFAULT_WEBSERVICE_FOLDER;
wsDelay = program.webserviceDelay;
- return _webserviceDelay = (wsDelay != null) && !isNaN(wsDelay) ? wsDelay : DEFAULT_WEBSERVICE_DELAY;
+ _webserviceDelay = (wsDelay != null) && !isNaN(wsDelay) ? wsDelay : DEFAULT_WEBSERVICE_DELAY;
+ return _isLiveReload = !!program.liveReload;
};
_now = function() {
if (_isVerbose) {
@@ -54,12 +57,24 @@
}
};
_fileTransferCallback = function(data) {
+ var content, contentType, payload, req;
switch (data.status) {
case "init":
return _rate = data.payload;
case "start":
+ if (_isLiveReload) {
+ payload = data.payload;
+ contentType = payload.contentType;
+ if (contentType === "text/html") {
+ req = payload.request;
+ content = payload.content;
+ content = livepage.insertLiveScript(content, contentType);
+ req.modifiedData = content;
+ req.modifiedDataSize = content.length;
+ }
+ }
if (_isVerbose) {
- return console.log("[".grey + ("started" + (_now())).yellow + "]".grey + (" " + data.payload));
+ return console.log("[".grey + ("started" + (_now())).yellow + "]".grey + (" " + payload.path));
}
break;
case "complete":
@@ -77,7 +92,7 @@
});
};
_init = function() {
- return connect.createServer(connect.bodyParser(), connect.query(), _router(), webservice(_root, _webserviceFolder, _webserviceDelay), connect.favicon(path.resolve(__dirname, "../public/favicon.ico")), connect.directory(_root), fileTransfer(_rate, _root, _fileTransferCallback));
+ return connect.createServer(connect.bodyParser(), connect.query(), _router(), livepage.live(_root, _isLiveReload), webservice(_root, _webserviceFolder, _webserviceDelay), connect.favicon(path.resolve(__dirname, "../public/favicon.ico")), connect.directory(_root), fileTransfer(_rate, _root, _fileTransferCallback));
};
/* bootstrap */
_version();
@@ -91,6 +106,7 @@
console.log(" root ".cyan + ("" + _root));
console.log(" port ".cyan + ("" + _port));
console.log(" rate ".cyan + (_rate != null ? "" + _rate + "(Bps)" : "unlimited"));
+ console.log(" livereload: ".cyan + ("" + _isLiveReload));
console.log(" webservice folder ".cyan + ("" + _webserviceFolder));
console.log(" webservice delay ".cyan + ("" + _webserviceDelay + " ms"));
if (_isVerbose) {
View
@@ -1,5 +1,5 @@
(function() {
- var absoluteDirPath, fs, getVersionNumber, normalizeFolderName, now, path, _packagePath, _root;
+ var absoluteDirPath, fs, getVersionNumber, normalizeFolderName, now, path, strSplice, _packagePath, _root;
path = require('path');
fs = require('fs');
_root = path.resolve(__dirname, "..");
@@ -45,9 +45,13 @@
nowArr = nowStr.split(' ');
return "" + nowArr[0] + " " + nowArr[2];
};
+ strSplice = function(string, idx, remove, subStr) {
+ return string.slice(0, idx) + subStr + string.slice(idx + Math.abs(remove));
+ };
/* exports */
exports.getVersionNumber = getVersionNumber;
exports.absoluteDirPath = absoluteDirPath;
exports.normalizeFolderName = normalizeFolderName;
exports.now = now;
+ exports.strSplice = strSplice;
}).call(this);
View
@@ -3,7 +3,7 @@
"name": "nserve",
"description": "A nodejs-powered static file server for development",
"keywords": ["static", "file", "web", "server"],
- "version": "0.0.5",
+ "version": "0.0.6",
"repository": {
"type": "git",
"url": "https://github.com/marty-wang/NServe"
Oops, something went wrong.

0 comments on commit f8e953b

Please sign in to comment.