|
|
@ -4,6 +4,7 @@ const path = require('path') |
|
|
|
const CommandLineTool = require('command-line-tool') |
|
|
|
const flatten = require('reduce-flatten') |
|
|
|
const arrayify = require('array-back') |
|
|
|
const ansi = require('ansi-escape-sequences') |
|
|
|
|
|
|
|
/** |
|
|
|
* @module local-web-server |
|
|
@ -42,30 +43,8 @@ class LocalWebServer { |
|
|
|
/* if the user did not supply a stack, use the default */ |
|
|
|
if (!stackPaths.length) stackPaths.push(path.resolve(__dirname, '..', 'node_modules', 'local-web-server-default-stack')) |
|
|
|
|
|
|
|
/* load the stack */ |
|
|
|
const stackModules = stackPaths |
|
|
|
.map(stackPath => loadStack(stackPath)) |
|
|
|
.map(Middleware => new Middleware()) |
|
|
|
.map(module => { |
|
|
|
if (module.stack) { |
|
|
|
const featureStack = module.stack() |
|
|
|
module.optionDefinitions = function () { |
|
|
|
return featureStack |
|
|
|
.map(Feature => new Feature()) |
|
|
|
.map(feature => feature.optionDefinitions && feature.optionDefinitions()) |
|
|
|
.filter(definitions => definitions) |
|
|
|
.reduce(flatten, []) |
|
|
|
} |
|
|
|
module.middleware = function (options) { |
|
|
|
return featureStack |
|
|
|
.map(Feature => new Feature()) |
|
|
|
.map(feature => feature.middleware(options)) |
|
|
|
.reduce(flatten, []) |
|
|
|
.filter(mw => mw) |
|
|
|
} |
|
|
|
} |
|
|
|
return module |
|
|
|
}) |
|
|
|
/* build the stack */ |
|
|
|
const stackModules = buildStack(stackPaths, this.onVerbose.bind(this), this.onDebug.bind(this)) |
|
|
|
|
|
|
|
/* gather stack option definitions and parse the command line */ |
|
|
|
const middlewareOptionDefinitions = stackModules |
|
|
@ -112,7 +91,14 @@ class LocalWebServer { |
|
|
|
this.options = options |
|
|
|
|
|
|
|
if (options.verbose) { |
|
|
|
// debug.setLevel(1)
|
|
|
|
stackModules |
|
|
|
.filter(mw => mw.on) |
|
|
|
.forEach(mw => mw.on('verbose', onVerbose)) |
|
|
|
} |
|
|
|
if (options.debug) { |
|
|
|
stackModules |
|
|
|
.filter(mw => mw.on) |
|
|
|
.forEach(mw => mw.on('debug', onDebug)) |
|
|
|
} |
|
|
|
|
|
|
|
/* --config */ |
|
|
@ -147,12 +133,7 @@ class LocalWebServer { |
|
|
|
|
|
|
|
app.use(compose(middlewareStack)) |
|
|
|
app.on('error', err => { |
|
|
|
const defaultLogInUse = this.stack.some(mw => mw.constructor.name === 'Log') |
|
|
|
if (defaultLogInUse) { |
|
|
|
if (this.options['log.format']) console.error(ansi.format(err.stack, 'red')) |
|
|
|
} else { |
|
|
|
console.error(ansi.format(err.stack, 'red')) |
|
|
|
} |
|
|
|
}) |
|
|
|
return app |
|
|
|
} |
|
|
@ -185,9 +166,27 @@ class LocalWebServer { |
|
|
|
server = http.createServer(app.callback()) |
|
|
|
} |
|
|
|
|
|
|
|
server.listen(options.port, onListening) |
|
|
|
const tableLayout = require('table-layout') |
|
|
|
|
|
|
|
server.listen(options.port, function () { |
|
|
|
const ipList = getIPList() |
|
|
|
.map(iface => `[underline]{${server.isHttps ? 'https' : 'http'}://${iface.address}:${options.port}}`) |
|
|
|
.join(', ') |
|
|
|
console.error(ansi.format('Serving at', 'bold'), ansi.format(ipList)) |
|
|
|
}) |
|
|
|
return server |
|
|
|
} |
|
|
|
|
|
|
|
onVerbose (title, msg) { |
|
|
|
if (this.options.verbose) { |
|
|
|
console.error(ansi.format(title, 'bold'), msg) |
|
|
|
} |
|
|
|
} |
|
|
|
onDebug (title, msg) { |
|
|
|
if (this.options.debug) { |
|
|
|
console.error(ansi.format(title, 'bold'), msg) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
@ -234,4 +233,49 @@ function isModule (module) { |
|
|
|
return module.prototype && (module.prototype.middleware || module.prototype.stack) |
|
|
|
} |
|
|
|
|
|
|
|
function getIPList () { |
|
|
|
const flatten = require('reduce-flatten') |
|
|
|
const os = require('os') |
|
|
|
|
|
|
|
let ipList = Object.keys(os.networkInterfaces()) |
|
|
|
.map(key => os.networkInterfaces()[key]) |
|
|
|
.reduce(flatten, []) |
|
|
|
.filter(iface => iface.family === 'IPv4') |
|
|
|
ipList.unshift({ address: os.hostname() }) |
|
|
|
return ipList |
|
|
|
} |
|
|
|
|
|
|
|
function buildStack (stackPaths, onVerbose, onDebug) { |
|
|
|
return stackPaths |
|
|
|
.map(stackPath => loadStack(stackPath)) |
|
|
|
.map(Middleware => new Middleware()) |
|
|
|
.map(module => { |
|
|
|
if (module.stack) { |
|
|
|
const featureStack = module.stack() |
|
|
|
.map(Feature => new Feature()) |
|
|
|
.map(feature => { |
|
|
|
if (feature.on) { |
|
|
|
feature.on('verbose', onVerbose) |
|
|
|
feature.on('debug', onDebug) |
|
|
|
} |
|
|
|
return feature |
|
|
|
}) |
|
|
|
|
|
|
|
module.optionDefinitions = function () { |
|
|
|
return featureStack |
|
|
|
.map(feature => feature.optionDefinitions && feature.optionDefinitions()) |
|
|
|
.filter(definitions => definitions) |
|
|
|
.reduce(flatten, []) |
|
|
|
} |
|
|
|
module.middleware = function (options) { |
|
|
|
return featureStack |
|
|
|
.map(feature => feature.middleware(options)) |
|
|
|
.reduce(flatten, []) |
|
|
|
.filter(mw => mw) |
|
|
|
} |
|
|
|
} |
|
|
|
return module |
|
|
|
}) |
|
|
|
} |
|
|
|
|
|
|
|
module.exports = LocalWebServer |