import * as opn from 'opn'
import * as color from 'cli-color'
import * as pathTool from 'path'
import * as koa from 'koa'
import * as staticCache from 'koa-static-cache'
import { devMiddleware, hotMiddleware } from 'koa2-webpack-middleware-plus'
import * as webpack from 'webpack'
import { httpProxy } from 'koa-http-proxy-middleware'
import { EventHelper } from 'event-helper'
export const devServer = (_options) => {
const options = {
port: Math.floor(Math.random() * 1001) + 7000,
autoOpenBrowser: true,
webpackConfig: null,
devConfig: {
publicPath: null,
quiet: true
},
hotConfig: {
log: false,
heartbeat: 2000,
reload: true
},
proxy: null,
staticPath: pathTool.join(process.cwd(), 'static'),
staticOptions: null,
..._options
}
return {
...EventHelper.create(),
readyPromise: null,
init(_options) {
Object.assign(options, _options)
this.runSteps()
return {
ready: this.readyPromise,
close: () => {
this.server.close()
}
}
},
getOptions() {
return { ...options }
},
runSteps() {
this.createApp()
.initMiddleware()
.mountMiddleware()
.listenAndOpen()
},
app: null,
_devMiddleware: null,
_hotMiddleware: null,
createApp() {
this.app = new koa()
this.compiler = webpack(options.webpackConfig)
return this
},
initMiddleware() {
this._devMiddleware = devMiddleware(this.compiler, {
publicPath: options.webpackConfig.output.publicPath,
quiet: true,
...options.devConfig
})
this._hotMiddleware = hotMiddleware(this.compiler, {
log: false,
heartbeat: 2000,
reload: true,
...options.hotConfig
})
this.compiler.plugin('compilation', function (compilation) {
compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
this.emit('template-change')
this._hotMiddleware.origin.publish({ action: 'reload' })
cb()
})
})
for (let proxyItem of options.proxy) {
if (typeof proxyItem === 'string') {
proxyItem = { target: proxyItem }
}
this.app.use(httpProxy(proxyItem.filter || context, proxyItem))
}
return this
},
mountMiddleware() {
this.app.use(this._devMiddleware)
this.app.use(this._hotMiddleware)
this.app.use(staticCache(options.staticPath, {
maxAge: 365 * 24 * 60 * 60,
...options.staticOptions
}))
return this
},
listenAndOpen() {
const uri = `http://localhost:${options.port}`
let _resolve
this.readyPromise = new Promise(resolve => { _resolve = resolve })
console.log(color.yellow('> Starting dev server...'))
this._devMiddleware.origin.waitUntilValid(() => {
this.emit('waiting')
console.log(color.bgWhite.greenBright('> Listening at ' + uri + '\n'))
if (options.autoOpenBrowser && process.env.NODE_ENV !== 'test') {
this.emit('open') !== false && opn(uri)
}
_resolve()
})
this.server = this.app.listen(options.port)
}
}
}