refactor, tests

This commit is contained in:
Lloyd Brookes
2016-06-29 22:40:34 +01:00
parent 84443a7ac5
commit 3d521399f6
6 changed files with 102 additions and 32 deletions

View File

@ -8,7 +8,7 @@
***Requires node v4.0.0 or higher. Install the [previous release](https://github.com/75lb/local-web-server/tree/prev) for older node support.*** ***Requires node v4.0.0 or higher. Install the [previous release](https://github.com/75lb/local-web-server/tree/prev) for older node support.***
# local-web-server # local-web-server
An application shell for building a simple, command-line web server for productive web development. An application shell for building a simple, command-line web server for productive web development. It contains no middleware of its own but will load default-stack unless you specify otherwise.
It is trivial is bundle and deploy with your project. Also deploys to heroku well for demo projects. It is trivial is bundle and deploy with your project. Also deploys to heroku well for demo projects.

View File

@ -4,7 +4,7 @@ exports.optionDefinitions = [
description: 'Web server port.', group: 'server' description: 'Web server port.', group: 'server'
}, },
{ {
name: 'stack', type: String, name: 'stack', type: String, multiple: true,
description: 'Middleware stack.', group: 'server' description: 'Middleware stack.', group: 'server'
}, },
{ {

View File

@ -18,13 +18,14 @@ const tool = new CommandLineTool()
* @extends module:middleware-stack * @extends module:middleware-stack
*/ */
class LocalWebServer { class LocalWebServer {
constructor (stack) { constructor (initOptions) {
initOptions = initOptions || {}
const commandLineArgs = require('command-line-args') const commandLineArgs = require('command-line-args')
const commandLineUsage = require('command-line-usage') const commandLineUsage = require('command-line-usage')
const cli = require('../lib/cli-data') const cli = require('../lib/cli-data')
/* manually scan for any --stack passed, as we may need to display stack options */ /* manually scan for any --stack passed, as we may need to display stack options */
const stackPaths = [] const stackPaths = initOptions.stack || []
const stackIndex = process.argv.indexOf('--stack') const stackIndex = process.argv.indexOf('--stack')
if (stackIndex > -1) { if (stackIndex > -1) {
for (var i = stackIndex + 1; i < process.argv.length; i++) { for (var i = stackIndex + 1; i < process.argv.length; i++) {
@ -38,11 +39,30 @@ class LocalWebServer {
} }
/* load the stack */ /* load the stack */
// if (!stackPaths.length) stackPaths.push('local-web-server-default-stack') if (!stackPaths.length) stackPaths.push(path.resolve(__dirname, '..', 'node_modules', 'local-web-server-default-stack'))
// console.log(stackPaths)
const stackModules = stackPaths const stackModules = stackPaths
.map(stackPath => loadStack(stackPath)) .map(stackPath => loadStack(stackPath))
.map(Middleware => new Middleware()) .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
})
/* gather stack option definitions and parse the command line */ /* gather stack option definitions and parse the command line */
const middlewareOptionDefinitions = stackModules const middlewareOptionDefinitions = stackModules
@ -67,11 +87,9 @@ class LocalWebServer {
/* combine in stored config */ /* combine in stored config */
const loadConfig = require('config-master') const loadConfig = require('config-master')
const stored = loadConfig('local-web-server') const stored = loadConfig('local-web-server')
options = Object.assign(stored, options.server, options.middleware, options.misc) options = Object.assign({ port: 8000 }, initOptions, stored, options.server, options.middleware, options.misc)
this.options = options this.options = options
// console.log(options)
if (options.verbose) { if (options.verbose) {
// debug.setLevel(1) // debug.setLevel(1)
} }
@ -95,33 +113,32 @@ class LocalWebServer {
.filter(mw => mw.middleware) .filter(mw => mw.middleware)
.map(mw => mw.middleware) .map(mw => mw.middleware)
.map(middleware => middleware(options)) .map(middleware => middleware(options))
.filter(middleware => middleware)
.reduce(flatten, []) .reduce(flatten, [])
.filter(middleware => middleware)
.map(convert) .map(convert)
this.stack = compose(middlewareStack) this.stack = compose(middlewareStack)
} }
} }
getApplication (options) { getApplication () {
const Koa = require('koa') const Koa = require('koa')
const app = new Koa() const app = new Koa()
app.use(this.stack) app.use(this.stack)
return app
}
getServer (options) {
const app = this.getApplication(options)
options = this.options
let key = options.key
let cert = options.cert
app.on('error', err => { app.on('error', err => {
if (options['log-format']) { if (this.options['log-format']) {
console.error(ansi.format(err.stack, 'red')) console.error(ansi.format(err.stack, 'red'))
} }
}) })
return app
}
if (options.https) { getServer () {
const app = this.getApplication()
const options = this.options
let key = options.key
let cert = options.cert
if (options.https && !(key && cert)) {
key = path.resolve(__dirname, '..', 'ssl', '127.0.0.1.key') key = path.resolve(__dirname, '..', 'ssl', '127.0.0.1.key')
cert = path.resolve(__dirname, '..', 'ssl', '127.0.0.1.crt') cert = path.resolve(__dirname, '..', 'ssl', '127.0.0.1.crt')
} }
@ -144,15 +161,19 @@ class LocalWebServer {
return server return server
} }
listen (options, callback) { listen () {
options = this.options const options = this.options
const server = this.getServer() const server = this._server = this.getServer()
const port = options.port || 8000 return new Promise ((resolve, reject) => {
server.listen(port, () => { server.listen(options.port, () => {
onServerUp(port, options.directory, server.isHttps) onServerUp(options.port, options.directory, server.isHttps)
if (callback) callback() resolve(server)
})
}) })
return server }
close () {
this._server.close()
} }
} }
@ -223,8 +244,8 @@ function loadStack (modulePath) {
} }
} }
} }
if (!module.prototype.middleware) { if (!(module && (module.prototype.middleware || module.prototype.stack))) {
tool.halt(new Error('Must supply a Middleware')) tool.halt(new Error('Not valid Middleware: ' + modulePath))
} }
return module return module
} }

View File

@ -46,6 +46,7 @@
"jsdoc-to-markdown": "^1.3.6", "jsdoc-to-markdown": "^1.3.6",
"koa-cache-control": "^1.0.0", "koa-cache-control": "^1.0.0",
"koa-livereload": "~0.2.0", "koa-livereload": "~0.2.0",
"node-fetch": "^1.5.3",
"req-then": "~0.2.4", "req-then": "~0.2.4",
"tape": "^4.6.0" "tape": "^4.6.0"
} }

12
test/test-middleware.js Normal file
View File

@ -0,0 +1,12 @@
'use strict'
class TestMiddleware {
middleware (option) {
return function (ctx, next) {
ctx.body = '1234512345'
return next()
}
}
}
module.exports = TestMiddleware

36
test/test.js Normal file
View File

@ -0,0 +1,36 @@
'use strict'
const test = require('tape')
const request = require('req-then')
const LocalWebServer = require('../')
const c = require('./common')
const path = require('path')
test('stack', function (t) {
t.plan(2)
const ws = new LocalWebServer({
stack: [ path.resolve(__dirname, 'test-middleware.js') ]
})
const server = ws.getServer()
server.listen(8100, () => {
request('http://localhost:8100/')
.then(c.checkResponse(t, 200, /1234512345/))
.then(server.close.bind(server))
.catch(c.fail(t))
})
})
test('https', function (t) {
t.plan(2)
const ws = new LocalWebServer({
stack: [ path.resolve(__dirname, 'test-middleware.js') ],
https: true,
port: 8100
})
ws.listen()
.then(() => {
request('https://localhost:8100/')
.then(c.checkResponse(t, 200, /1234512345/))
.then(ws.close.bind(ws))
.catch(c.fail(t))
})
})