diff --git a/README.md b/README.md index c2053e3..779a6e6 100644 --- a/README.md +++ b/README.md @@ -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.*** # 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. diff --git a/lib/cli-data.js b/lib/cli-data.js index b1d4eb2..716326b 100644 --- a/lib/cli-data.js +++ b/lib/cli-data.js @@ -4,7 +4,7 @@ exports.optionDefinitions = [ description: 'Web server port.', group: 'server' }, { - name: 'stack', type: String, + name: 'stack', type: String, multiple: true, description: 'Middleware stack.', group: 'server' }, { diff --git a/lib/local-web-server.js b/lib/local-web-server.js index 72c6e48..dabf476 100644 --- a/lib/local-web-server.js +++ b/lib/local-web-server.js @@ -18,13 +18,14 @@ const tool = new CommandLineTool() * @extends module:middleware-stack */ class LocalWebServer { - constructor (stack) { + constructor (initOptions) { + initOptions = initOptions || {} const commandLineArgs = require('command-line-args') const commandLineUsage = require('command-line-usage') const cli = require('../lib/cli-data') /* 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') if (stackIndex > -1) { for (var i = stackIndex + 1; i < process.argv.length; i++) { @@ -38,11 +39,30 @@ class LocalWebServer { } /* load the stack */ - // if (!stackPaths.length) stackPaths.push('local-web-server-default-stack') - // console.log(stackPaths) + if (!stackPaths.length) stackPaths.push(path.resolve(__dirname, '..', 'node_modules', 'local-web-server-default-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 + }) /* gather stack option definitions and parse the command line */ const middlewareOptionDefinitions = stackModules @@ -67,11 +87,9 @@ class LocalWebServer { /* combine in stored config */ const loadConfig = require('config-master') 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 - // console.log(options) - if (options.verbose) { // debug.setLevel(1) } @@ -95,33 +113,32 @@ class LocalWebServer { .filter(mw => mw.middleware) .map(mw => mw.middleware) .map(middleware => middleware(options)) - .filter(middleware => middleware) .reduce(flatten, []) + .filter(middleware => middleware) .map(convert) this.stack = compose(middlewareStack) } } - getApplication (options) { + getApplication () { const Koa = require('koa') const app = new Koa() app.use(this.stack) + app.on('error', err => { + if (this.options['log-format']) { + console.error(ansi.format(err.stack, 'red')) + } + }) return app } - getServer (options) { - const app = this.getApplication(options) - options = this.options + getServer () { + const app = this.getApplication() + const options = this.options let key = options.key let cert = options.cert - app.on('error', err => { - if (options['log-format']) { - console.error(ansi.format(err.stack, 'red')) - } - }) - - if (options.https) { + if (options.https && !(key && cert)) { key = path.resolve(__dirname, '..', 'ssl', '127.0.0.1.key') cert = path.resolve(__dirname, '..', 'ssl', '127.0.0.1.crt') } @@ -144,15 +161,19 @@ class LocalWebServer { return server } - listen (options, callback) { - options = this.options - const server = this.getServer() - const port = options.port || 8000 - server.listen(port, () => { - onServerUp(port, options.directory, server.isHttps) - if (callback) callback() + listen () { + const options = this.options + const server = this._server = this.getServer() + return new Promise ((resolve, reject) => { + server.listen(options.port, () => { + onServerUp(options.port, options.directory, server.isHttps) + resolve(server) + }) }) - return server + } + + close () { + this._server.close() } } @@ -223,8 +244,8 @@ function loadStack (modulePath) { } } } - if (!module.prototype.middleware) { - tool.halt(new Error('Must supply a Middleware')) + if (!(module && (module.prototype.middleware || module.prototype.stack))) { + tool.halt(new Error('Not valid Middleware: ' + modulePath)) } return module } diff --git a/package.json b/package.json index f097539..1439c92 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "jsdoc-to-markdown": "^1.3.6", "koa-cache-control": "^1.0.0", "koa-livereload": "~0.2.0", + "node-fetch": "^1.5.3", "req-then": "~0.2.4", "tape": "^4.6.0" } diff --git a/test/test-middleware.js b/test/test-middleware.js new file mode 100644 index 0000000..137438c --- /dev/null +++ b/test/test-middleware.js @@ -0,0 +1,12 @@ +'use strict' + +class TestMiddleware { + middleware (option) { + return function (ctx, next) { + ctx.body = '1234512345' + return next() + } + } +} + +module.exports = TestMiddleware diff --git a/test/test.js b/test/test.js new file mode 100644 index 0000000..a8a7a7c --- /dev/null +++ b/test/test.js @@ -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)) + }) +})