Socket
Socket
Sign inDemoInstall

live-server

Package Overview
Dependencies
Maintainers
1
Versions
24
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

live-server - npm Package Compare versions

Comparing version 1.1.0 to 1.2.0

middleware/example.js

6

CONTRIBUTING.md

@@ -11,6 +11,10 @@ Contributing Guidelines

* Does my code adhere to the project's coding style (observable from surrounding code)?
* Can backwards compatibility be preserved?
A few guiding principles: keep the app simple and small, focusing on what it's meant to provide: live reloading development web server. Avoid extra dependencies and the need to do configuration when possible and it makes sense. Minimize bloat.
If you are adding a feature, think about if it could be an extenral middleware instead, possible bundled with `live-server` in its `middleware` folder.
**New features should come with test cases!**
**Run `npm test` to check that you are not introducing new bugs or style issues!**

177

index.js

@@ -13,3 +13,4 @@ #!/usr/bin/env node

es = require("event-stream"),
watchr = require('watchr');
os = require('os'),
chokidar = require('chokidar');
require('colors');

@@ -21,3 +22,3 @@

server: null,
watchers: [],
watcher: null,
logLevel: 2

@@ -35,3 +36,3 @@ };

// Based on connect.static(), but streamlined and with added code injecter
function staticServer(root, spa) {
function staticServer(root) {
var isFile = false;

@@ -47,13 +48,5 @@ try { // For supporting mounting files instead of just directories

var hasNoOrigin = !req.headers.origin;
var injectCandidates = [ new RegExp("</body>", "i"), new RegExp("</svg>") ];
var injectCandidates = [ new RegExp("</body>", "i"), new RegExp("</svg>"), new RegExp("</head>", "i")];
var injectTag = null;
// Single Page App - redirect handler
if (spa && req.url !== '/') {
var route = req.url;
req.url = '/';
res.statusCode = 302;
res.setHeader('Location', req.url + '#' + route);
}
function directory() {

@@ -97,4 +90,4 @@ var pathname = url.parse(req.originalUrl).pathname;

var originalPipe = stream.pipe;
stream.pipe = function(res) {
originalPipe.call(stream, es.replace(new RegExp(injectTag, "i"), INJECTED_CODE + injectTag)).pipe(res);
stream.pipe = function(resp) {
originalPipe.call(stream, es.replace(new RegExp(injectTag, "i"), INJECTED_CODE + injectTag)).pipe(resp);
};

@@ -135,3 +128,3 @@ }

* @param ignorePattern {regexp} Ignore files by RegExp
* @param open {string} Subpath to open in browser, use false to suppress launch (default: server root)
* @param open {(string|string[])} Subpath(s) to open in browser, use false to suppress launch (default: server root)
* @param mount {array} Mount directories onto a route, e.g. [['/components', './node_modules']].

@@ -154,7 +147,6 @@ * @param logLevel {number} 0 = errors only, 1 = some, 2 = lots

"" : ((options.open === null || options.open === false) ? null : options.open);
var spa = options.spa || false;
if (options.noBrowser) openPath = null; // Backwards compatibility with 0.7.0
var file = options.file;
var staticServerHandler = staticServer(root, spa);
var wait = options.wait || 0;
var staticServerHandler = staticServer(root);
var wait = options.wait === undefined ? 100 : options.wait;
var browser = options.browser || null;

@@ -170,4 +162,26 @@ var htpasswd = options.htpasswd || null;

// Add logger. Level 2 logs only errors
if (LiveServer.logLevel === 2) {
app.use(logger('dev', {
skip: function (req, res) { return res.statusCode < 400; }
}));
// Level 2 or above logs all requests
} else if (LiveServer.logLevel > 2) {
app.use(logger('dev'));
}
if (options.spa) {
middleware.push("spa");
}
// Add middleware
middleware.map(app.use.bind(app));
middleware.map(function(mw) {
if (typeof mw === "string") {
var ext = path.extname(mw).toLocaleLowerCase();
if (ext !== ".js") {
mw = require(path.join(__dirname, "middleware", mw + ".js"));
} else {
mw = require(mw);
}
}
app.use(mw);
});

@@ -208,8 +222,9 @@ // Use http-auth if configured

.use(serveIndex(root, { icons: true }));
if (LiveServer.logLevel >= 2)
app.use(logger('dev'));
var server, protocol;
if (https !== null) {
var httpsConfig = require(path.resolve(process.cwd(), https));
var httpsConfig = https;
if (typeof https === "string") {
httpsConfig = require(path.resolve(process.cwd(), https));
}
server = require("https").createServer(httpsConfig, app);

@@ -247,6 +262,31 @@ protocol = "https";

var serveURLs = [ serveURL ];
if (LiveServer.logLevel > 2 && address.address === "0.0.0.0") {
var ifaces = os.networkInterfaces();
serveURLs = Object.keys(ifaces)
.map(function(iface) {
return ifaces[iface];
})
// flatten address data, use only IPv4
.reduce(function(data, addresses) {
addresses.filter(function(addr) {
return addr.family === "IPv4";
}).forEach(function(addr) {
data.push(addr);
});
return data;
}, [])
.map(function(addr) {
return protocol + "://" + addr.address + ":" + address.port;
});
}
// Output
if (LiveServer.logLevel >= 1) {
if (serveURL === openURL)
console.log(("Serving \"%s\" at %s").green, root, serveURL);
if (serveURLs.length === 1) {
console.log(("Serving \"%s\" at %s").green, root, serveURLs[0]);
} else {
console.log(("Serving \"%s\" at\n\t%s").green, root, serveURLs.join("\n\t"));
}
else

@@ -258,3 +298,9 @@ console.log(("Serving \"%s\" at %s (%s)").green, root, openURL, serveURL);

if (openPath !== null)
open(openURL + openPath, {app: browser});
if (typeof openPath === "object") {
openPath.forEach(function(p) {
open(openURL + p, {app: browser});
});
} else {
open(openURL + openPath, {app: browser});
}
});

@@ -272,6 +318,5 @@

if (wait > 0) {
(function(ws) {
(function() {
var wssend = ws.send;
var waitTimeout;
ws.send = function() {

@@ -284,3 +329,3 @@ var args = arguments;

};
})(ws);
})();
}

@@ -297,36 +342,43 @@

var ignored = [
function(testPath) { // Always ignore dotfiles (important e.g. because editor hidden temp files)
return testPath !== "." && /(^[.#]|(?:__|~)$)/.test(path.basename(testPath));
}
];
if (options.ignore) {
ignored = ignored.concat(options.ignore);
}
if (options.ignorePattern) {
ignored.push(options.ignorePattern);
}
// Setup file watcher
watchr.watch({
paths: watchPaths,
ignorePaths: options.ignore || false,
ignoreCommonPatterns: true,
ignoreHiddenFiles: true,
ignoreCustomPatterns: options.ignorePattern || null,
preferredMethods: [ 'watchFile', 'watch' ],
interval: 1407,
listeners: {
error: function(err) {
console.log("ERROR:".red, err);
},
change: function(eventName, filePath /*, fileCurrentStat, filePreviousStat*/) {
clients.forEach(function(ws) {
if (!ws) return;
if (path.extname(filePath) === ".css") {
ws.send('refreshcss');
if (LiveServer.logLevel >= 1)
console.log("CSS change detected".magenta, filePath);
} else {
ws.send('reload');
if (LiveServer.logLevel >= 1)
console.log("File change detected".cyan, filePath);
}
});
}
},
next: function(err, watchers) {
if (err)
console.error("Error watching files:".red, err);
LiveServer.watchers = watchers;
LiveServer.watcher = chokidar.watch(watchPaths, {
ignored: ignored,
ignoreInitial: true
});
function handleChange(changePath) {
var cssChange = path.extname(changePath) === ".css";
if (LiveServer.logLevel >= 1) {
if (cssChange)
console.log("CSS change detected".magenta, changePath);
else console.log("Change detected".cyan, changePath);
}
});
clients.forEach(function(ws) {
if (ws)
ws.send(cssChange ? 'refreshcss' : 'reload');
});
}
LiveServer.watcher
.on("change", handleChange)
.on("add", handleChange)
.on("unlink", handleChange)
.on("addDir", handleChange)
.on("unlinkDir", handleChange)
.on("ready", function () {
if (LiveServer.logLevel >= 1)
console.log("Ready for changes".cyan);
})
.on("error", function (err) {
console.log("ERROR:".red, err);
});

@@ -337,6 +389,5 @@ return server;

LiveServer.shutdown = function() {
var watchers = LiveServer.watchers;
if (watchers) {
for (var i = 0; i < watchers.length; ++i)
watchers[i].close();
var watcher = LiveServer.watcher;
if (watcher) {
watcher.close();
}

@@ -343,0 +394,0 @@ var server = LiveServer.server;

@@ -13,3 +13,4 @@ #!/usr/bin/env node

proxy: [],
logLevel: 2
middleware: [],
logLevel: 2,
};

@@ -44,3 +45,13 @@

}
opts.open = open;
switch (typeof opts.open) {
case "boolean":
opts.open = open;
break;
case "string":
opts.open = [opts.open, open];
break;
case "object":
opts.open.push(open);
break;
}
process.argv.splice(i, 1);

@@ -78,3 +89,3 @@ }

else if (arg === "--spa") {
opts.spa = true;
opts.middleware.push("spa");
process.argv.splice(i, 1);

@@ -86,7 +97,12 @@ }

}
else if (arg === "--verbose" || arg === "-V") {
opts.logLevel = 3;
process.argv.splice(i, 1);
}
else if (arg.indexOf("--mount=") > -1) {
// e.g. "--mount=/components:./node_modules" will be ['/components', '<process.cwd()>/node_modules']
var mountRule = arg.substring(8).split(":");
mountRule[1] = path.resolve(process.cwd(), mountRule[1]);
opts.mount.push(mountRule);
// split only on the first ":", as the path may contain ":" as well (e.g. C:\file.txt)
var match = arg.substring(8).match(/([^:]+):(.+)$/);
match[2] = path.resolve(process.cwd(), match[2]);
opts.mount.push([ match[1], match[2] ]);
process.argv.splice(i, 1);

@@ -125,2 +141,6 @@ }

}
else if (arg.indexOf("--middleware=") > -1) {
opts.middleware.push(arg.substring(13));
process.argv.splice(i, 1);
}
else if (arg === "--help" || arg === "-h") {

@@ -127,0 +147,0 @@ console.log('Usage: live-server [-v|--version] [-h|--help] [-q|--quiet] [--port=PORT] [--host=HOST] [--open=PATH] [--no-browser] [--browser=BROWSER] [--ignore=PATH] [--ignorePattern=RGXP] [--entry-file=PATH] [--spa] [--mount=ROUTE:PATH] [--wait=MILLISECONDS] [--htpasswd=PATH] [--cors] [--https=PATH] [--proxy=PATH] [PATH]');

{
"name": "live-server",
"version": "1.1.0",
"version": "1.2.0",
"description": "simple development http server with live reload capability",

@@ -15,8 +15,9 @@ "keywords": [

"dependencies": {
"chokidar": "^1.6.0",
"colors": "latest",
"connect": "3.4.x",
"connect": "3.5.x",
"cors": "latest",
"event-stream": "latest",
"faye-websocket": "0.11.x",
"http-auth": "2.4.x",
"http-auth": "3.1.x",
"morgan": "^1.6.1",

@@ -27,9 +28,8 @@ "object-assign": "latest",

"send": "latest",
"serve-index": "^1.7.2",
"watchr": "2.6.x"
"serve-index": "^1.7.2"
},
"devDependencies": {
"mocha": "^2.3.3",
"supertest": "^1.0.1",
"eslint": "^2.8.0",
"mocha": "^3.2.0",
"supertest": "^2.0.1",
"eslint": "^3.13.0",
"jshint": "^2.9.2"

@@ -36,0 +36,0 @@ },

@@ -50,11 +50,13 @@ [![view on npm](http://img.shields.io/npm/v/live-server.svg)](https://www.npmjs.org/package/live-server)

* `--browser=BROWSER` - specify browser to use instead of system default
* `--quiet` - suppress logging
* `--quiet | -q` - suppress logging
* `--verbose | -V` - more logging (logs all requests, shows all listening IPv4 interfaces, etc.)
* `--open=PATH` - launch browser to PATH instead of server root
* `--watch=PATH` - comma-separated string of paths to exclusively watch for changes (default: watch everything)
* `--ignore=PATH` - comma-separated string of paths to ignore
* `--ignorePattern=RGXP` - Regular expression of files to ignore (ie `.*\.jade`)
* `--entry-file=PATH` - serve this file in place of missing files (useful for single page apps)
* `--ignore=PATH` - comma-separated string of paths to ignore ([anymatch](https://github.com/es128/anymatch)-compatible definition)
* `--ignorePattern=RGXP` - Regular expression of files to ignore (ie `.*\.jade`) (**DEPRECATED** in favor of `--ignore`)
* `--middleware=PATH` - path to .js file exporting a middleware function to add; can be a name without path nor extension to reference bundled middlewares in `middleware` folder
* `--entry-file=PATH` - serve this file (server root relative) in place of missing files (useful for single page apps)
* `--mount=ROUTE:PATH` - serve the paths contents under the defined route (multiple definitions possible)
* `--spa` - translate requests from /abc to /#/abc (handy for Single Page Apps)
* `--wait=MILLISECONDS` - wait for all changes, before reloading
* `--wait=MILLISECONDS` - (default 100ms) wait for all changes, before reloading
* `--htpasswd=PATH` - Enables http-auth expecting htpasswd file located at PATH

@@ -81,3 +83,3 @@ * `--cors` - Enables CORS for any origin (reflects request origin, requests with credentials are supported)

host: "0.0.0.0", // Set the address to bind to. Defaults to 0.0.0.0 or process.env.IP.
root: "/public", // Set root directory that's being server. Defaults to cwd.
root: "/public", // Set root directory that's being served. Defaults to cwd.
open: false, // When false, it won't load your browser by default.

@@ -112,8 +114,15 @@ ignore: 'scss,my/templates', // comma-separated string for paths to ignore

If using the node API, you can also directly pass a configuration object instead of a path to the module.
Troubleshooting
---------------
Open your browser's console: there should be a message at the top stating that live reload is enabled. Note that you will need a browser that supports WebSockets. If there are errors, deal with them. If it's still not working, [file an issue](https://github.com/tapio/live-server/issues).
* No reload on changes
* Open your browser's console: there should be a message at the top stating that live reload is enabled. Note that you will need a browser that supports WebSockets. If there are errors, deal with them. If it's still not working, [file an issue](https://github.com/tapio/live-server/issues).
* Error: watch <PATH> ENOSPC
* See [this suggested solution](http://stackoverflow.com/questions/22475849/node-js-error-enospc/32600959#32600959).
* Reload works but changes are missing or outdated
* Try using `--wait=MS` option. Where `MS` is time in milliseconds to wait before issuing a reload.
How it works

@@ -134,2 +143,15 @@ ------------

* v1.2.0
- Add `--middleware` parameter to use external middlewares
- `middleware` API parameter now also accepts strings similar to `--middleware`
- Changed file watcher to improve speed (@pavel)
- `--ignore` now accepts regexps and globs, `--ignorePattern` deprecated (@pavel)
- Added `--verbose` cli option (logLevel 3) (@pavel)
- Logs all requests, displays warning when can't inject html file, displays all listening IPv4 interfaces...
- HTTPS configuration now also accepts a plain object (@pavel)
- Move `--spa` to a bundled middleware file
- New bundled `spa-no-assets` middleware that works like `spa` but ignores requests with extension
- Allow multiple `--open` arguments (@PirtleShell)
- Inject to `head` if `body` not found (@pmd1991)
- Update dependencies
* v1.1.0

@@ -136,0 +158,0 @@ - Proxy support (@pavel)

@@ -31,2 +31,9 @@ var request = require('supertest');

});
it('should inject to <head> when no <body>', function(done){
request(liveServer)
.get('/index-head.html')
.expect('Content-Type', 'text/html; charset=UTF-8')
.expect(/<script [^]+?live reload enabled[^]+?<\/script>/i)
.expect(200, done);
});
it('should inject also svg files', function(done){

@@ -42,2 +49,12 @@ request(liveServer)

});
it('should not inject html fragments', function(done){
request(liveServer)
.get('/fragment.html')
.expect('Content-Type', 'text/html; charset=UTF-8')
.expect(function(res) {
if (res.text.toString().indexOf("Live reload enabled") > -1)
throw new Error("injected code should not be found");
})
.expect(200, done);
});
xit('should have WebSocket connection', function(done){

@@ -44,0 +61,0 @@ done(); // todo

var request = require('supertest');
var path = require('path');
var liveServer = require('..').start({
root: path.join(__dirname, 'data'),
port: 0,
open: false,
https: path.join(__dirname, 'conf/https.conf.js')
});
// accept self-signed certificates
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
describe('https tests', function() {
function tests(liveServer) {
it('should reply with a correct index file', function(done) {

@@ -26,4 +20,30 @@ request(liveServer)

});
}
describe('https tests with external module', function() {
var opts = {
root: path.join(__dirname, 'data'),
port: 0,
open: false,
https: path.join(__dirname, 'conf/https.conf.js')
};
var liveServer = require("..").start(opts);
tests(liveServer);
after(function () {
liveServer.close()
});
});
describe('https tests with object', function() {
var opts = {
root: path.join(__dirname, 'data'),
port: 0,
open: false,
https: require(path.join(__dirname, 'conf/https.conf.js'))
};
var liveServer = require("..").start(opts);
tests(liveServer);
after(function () {
liveServer.close()
});
});
var request = require('supertest');
var path = require('path');
var liveServer = require('..').start({
var liveServer1 = require('..').start({
root: path.join(__dirname, 'data'),

@@ -14,9 +14,31 @@ port: 0,

});
var liveServer2 = require('..').start({
root: path.join(__dirname, 'data'),
port: 0,
open: false,
middleware: [ "example" ]
});
var liveServer3 = require('..').start({
root: path.join(__dirname, 'data'),
port: 0,
open: false,
middleware: [ path.join(__dirname, 'data', 'middleware.js') ]
});
describe('middleware tests', function() {
it("should respond with middleware's status code", function(done) {
request(liveServer)
it("should respond with middleware function's status code", function(done) {
request(liveServer1)
.get('/')
.expect(201, done);
});
it("should respond with built-in middleware's status code", function(done) {
request(liveServer2)
.get('/')
.expect(202, done);
});
it("should respond with external middleware's status code", function(done) {
request(liveServer3)
.get('/')
.expect(203, done);
});
});

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc