|
@ -39,7 +39,8 @@ function localWebServer (options) { |
|
|
compress: false, |
|
|
compress: false, |
|
|
mime: {}, |
|
|
mime: {}, |
|
|
forbid: [], |
|
|
forbid: [], |
|
|
rewrite: [] |
|
|
|
|
|
|
|
|
rewrite: [], |
|
|
|
|
|
verbose: false |
|
|
}, options) |
|
|
}, options) |
|
|
|
|
|
|
|
|
const log = options.log |
|
|
const log = options.log |
|
@ -48,6 +49,16 @@ function localWebServer (options) { |
|
|
const app = new Koa() |
|
|
const app = new Koa() |
|
|
const _use = app.use |
|
|
const _use = app.use |
|
|
app.use = x => _use.call(app, convert(x)) |
|
|
app.use = x => _use.call(app, convert(x)) |
|
|
|
|
|
function verbose (category, message) { |
|
|
|
|
|
if (options.verbose) { |
|
|
|
|
|
process.nextTick(() => app.emit('verbose', category, message)) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
app._verbose = verbose |
|
|
|
|
|
|
|
|
|
|
|
if (options.verbose && !log.format) { |
|
|
|
|
|
log.format = 'none' |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/* CORS: allow from any origin */ |
|
|
/* CORS: allow from any origin */ |
|
|
app.use(cors()) |
|
|
app.use(cors()) |
|
@ -57,9 +68,11 @@ function localWebServer (options) { |
|
|
options.rewrite.forEach(route => { |
|
|
options.rewrite.forEach(route => { |
|
|
if (route.to) { |
|
|
if (route.to) { |
|
|
if (url.parse(route.to).host) { |
|
|
if (url.parse(route.to).host) { |
|
|
app.use(_.all(route.from, proxyRequest(route))) |
|
|
|
|
|
|
|
|
verbose('proxy rewrite', `${route.from} -> ${route.to}`) |
|
|
|
|
|
app.use(_.all(route.from, proxyRequest(route, app))) |
|
|
} else { |
|
|
} else { |
|
|
const rewrite = require('koa-rewrite') |
|
|
const rewrite = require('koa-rewrite') |
|
|
|
|
|
verbose('local rewrite', `${route.from} -> ${route.to}`) |
|
|
app.use(rewrite(route.from, route.to)) |
|
|
app.use(rewrite(route.from, route.to)) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
@ -68,6 +81,7 @@ function localWebServer (options) { |
|
|
|
|
|
|
|
|
/* path blacklist */ |
|
|
/* path blacklist */ |
|
|
if (options.forbid.length) { |
|
|
if (options.forbid.length) { |
|
|
|
|
|
verbose('forbid', options.forbid.join(', ')) |
|
|
app.use(blacklist(options.forbid)) |
|
|
app.use(blacklist(options.forbid)) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -75,12 +89,14 @@ function localWebServer (options) { |
|
|
if (!options['no-cache']) { |
|
|
if (!options['no-cache']) { |
|
|
const conditional = require('koa-conditional-get') |
|
|
const conditional = require('koa-conditional-get') |
|
|
const etag = require('koa-etag') |
|
|
const etag = require('koa-etag') |
|
|
|
|
|
verbose('etag caching', 'enabled') |
|
|
app.use(conditional()) |
|
|
app.use(conditional()) |
|
|
app.use(etag()) |
|
|
app.use(etag()) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* mime-type overrides */ |
|
|
/* mime-type overrides */ |
|
|
if (options.mime) { |
|
|
if (options.mime) { |
|
|
|
|
|
verbose('mime override', JSON.stringify(options.mime)) |
|
|
app.use((ctx, next) => { |
|
|
app.use((ctx, next) => { |
|
|
return next().then(() => { |
|
|
return next().then(() => { |
|
|
const reqPathExtension = path.extname(ctx.path).slice(1) |
|
|
const reqPathExtension = path.extname(ctx.path).slice(1) |
|
@ -95,6 +111,7 @@ function localWebServer (options) { |
|
|
/* compress response */ |
|
|
/* compress response */ |
|
|
if (options.compress) { |
|
|
if (options.compress) { |
|
|
const compress = require('koa-compress') |
|
|
const compress = require('koa-compress') |
|
|
|
|
|
verbose('compression', 'enabled') |
|
|
app.use(compress()) |
|
|
app.use(compress()) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -117,18 +134,21 @@ function localWebServer (options) { |
|
|
/* serve static files */ |
|
|
/* serve static files */ |
|
|
if (options.static.root) { |
|
|
if (options.static.root) { |
|
|
const serve = require('koa-static') |
|
|
const serve = require('koa-static') |
|
|
|
|
|
verbose('static', `root: ${options.static.root} options: ${JSON.stringify(options.static.options)}` ) |
|
|
app.use(serve(options.static.root, options.static.options)) |
|
|
app.use(serve(options.static.root, options.static.options)) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* serve directory index */ |
|
|
/* serve directory index */ |
|
|
if (options.serveIndex.path) { |
|
|
if (options.serveIndex.path) { |
|
|
const serveIndex = require('koa-serve-index') |
|
|
const serveIndex = require('koa-serve-index') |
|
|
|
|
|
verbose('serve-index', `root: ${options.serveIndex.path} options: ${JSON.stringify(options.serveIndex.options)}` ) |
|
|
app.use(serveIndex(options.serveIndex.path, options.serveIndex.options)) |
|
|
app.use(serveIndex(options.serveIndex.path, options.serveIndex.options)) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* for any URL not matched by static (e.g. `/search`), serve the SPA */ |
|
|
/* for any URL not matched by static (e.g. `/search`), serve the SPA */ |
|
|
if (options.spa) { |
|
|
if (options.spa) { |
|
|
const send = require('koa-send') |
|
|
const send = require('koa-send') |
|
|
|
|
|
verbose('SPA', options.spa) |
|
|
app.use(_.all('*', function * () { |
|
|
app.use(_.all('*', function * () { |
|
|
yield send(this, options.spa, { root: path.resolve(options.static.root) || process.cwd() }) |
|
|
yield send(this, options.spa, { root: path.resolve(options.static.root) || process.cwd() }) |
|
|
})) |
|
|
})) |
|
@ -141,7 +161,7 @@ function logstalgiaDate () { |
|
|
return (`${d.getDate()}/${d.getUTCMonth()}/${d.getFullYear()}:${d.toTimeString()}`).replace('GMT', '').replace(' (BST)', '') |
|
|
return (`${d.getDate()}/${d.getUTCMonth()}/${d.getFullYear()}:${d.toTimeString()}`).replace('GMT', '').replace(' (BST)', '') |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function proxyRequest (route) { |
|
|
|
|
|
|
|
|
function proxyRequest (route, app) { |
|
|
const httpProxy = require('http-proxy') |
|
|
const httpProxy = require('http-proxy') |
|
|
const proxy = httpProxy.createProxyServer({ |
|
|
const proxy = httpProxy.createProxyServer({ |
|
|
changeOrigin: true |
|
|
changeOrigin: true |
|
@ -168,12 +188,13 @@ function proxyRequest (route) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
this.response = false |
|
|
this.response = false |
|
|
|
|
|
app._verbose('proxy request', `from: ${this.path}, to: ${url.parse(route.new).href}`) |
|
|
|
|
|
|
|
|
proxy.once('error', err => { |
|
|
proxy.once('error', err => { |
|
|
this.throw(500, `[PROXY] ${err.message}: ${route.new}`) |
|
|
this.throw(500, `[PROXY] ${err.message}: ${route.new}`) |
|
|
}) |
|
|
}) |
|
|
proxy.once('proxyReq', function (proxyReq) { |
|
|
proxy.once('proxyReq', function (proxyReq) { |
|
|
proxyReq.path = url.parse(route.new).path; |
|
|
|
|
|
|
|
|
proxyReq.path = url.parse(route.new).path |
|
|
}) |
|
|
}) |
|
|
proxy.web(this.req, this.res, { target: route.new }) |
|
|
proxy.web(this.req, this.res, { target: route.new }) |
|
|
} |
|
|
} |
|
|