backend: router hot-reloading

This commit is contained in:
41666 2019-02-25 00:47:08 -06:00
parent 11cf1d4805
commit 959a2eb46f
4 changed files with 53 additions and 20 deletions

View file

@ -3,16 +3,17 @@ const Sequelize = require('sequelize')
const fetchModels = require('./models')
const fetchApis = require('./api')
const Next = require('next')
const betterRouter = require('koa-better-router')
class Roleypoly {
constructor (router, io, app) {
this.router = router
constructor (io, app) {
this.io = io
this.ctx = {}
this.ctx.config = {
appUrl: process.env.APP_URL
appUrl: process.env.APP_URL,
dev: process.env.NODE_ENV !== 'production',
hotReload: process.env.NO_HOT_RELOAD !== '1'
}
this.ctx.io = io
@ -52,10 +53,11 @@ class Roleypoly {
this.ctx.P = new (require('./services/presentation'))(this.ctx)
}
async mountRoutes () {
async loadRoutes (forceClear = false) {
await this.ctx.ui.prepare()
fetchApis(this.router, this.ctx)
this.router = betterRouter().loadMethods()
fetchApis(this.router, this.ctx, { forceClear })
// after routing, add the * for ui handler
this.router.get('*', async ctx => {
@ -63,7 +65,31 @@ class Roleypoly {
ctx.respond = false
})
this.__app.use(this.router.middleware())
return this.router.middleware()
}
async mountRoutes () {
let mw = await this.loadRoutes()
if (this.ctx.config.dev && this.ctx.config.hotReload) {
// hot-reloading system
log.info('API hot-reloading is active.')
const chokidar = require('chokidar')
let hotMiddleware = mw
this.__apiWatcher = chokidar.watch('api/**')
this.__apiWatcher.on('all', async (path) => {
log.info('reloading APIs...', path)
hotMiddleware = await this.loadRoutes(true)
})
// custom passthrough so we use a specially scoped middleware.
mw = (ctx, next) => {
return hotMiddleware(ctx, next)
}
}
this.__app.use(mw)
}
}

View file

@ -3,7 +3,7 @@ const glob = require('glob')
const PROD = process.env.NODE_ENV === 'production'
module.exports = async (router, ctx) => {
module.exports = async (router, ctx, { forceClear = false } = {}) => {
const apis = glob.sync(`./api/**/!(index).js`)
log.debug('found apis', apis)
@ -14,7 +14,11 @@ module.exports = async (router, ctx) => {
}
log.debug(`mounting ${a}`)
try {
require(a.replace('api/', ''))(router, ctx)
const pathname = a.replace('api/', '')
if (forceClear) {
delete require.cache[require.resolve(pathname)]
}
require(pathname)(router, ctx)
} catch (e) {
log.error(`couldn't mount ${a}`, e)
}

View file

@ -1,13 +1,10 @@
require('dotenv').config({silent: true})
require('dotenv').config({ silent: true })
const log = new (require('./logger'))('index')
const http = require('http')
const Koa = require('koa')
const app = new Koa()
const _io = require('socket.io')
const fs = require('fs')
const path = require('path')
const router = require('koa-better-router')().loadMethods()
const Roleypoly = require('./Roleypoly')
const ksuid = require('ksuid')
@ -20,7 +17,7 @@ Array.prototype.areduce = async function (predicate, acc = []) { // eslint-disab
return acc
}
Array.prototype.filterNot = Array.prototype.filterNot || function (predicate) {
Array.prototype.filterNot = Array.prototype.filterNot || function (predicate) { // eslint-disable-line
return this.filter(v => !predicate(v))
}
@ -28,9 +25,7 @@ Array.prototype.filterNot = Array.prototype.filterNot || function (predicate) {
const server = http.createServer(app.callback())
const io = _io(server, { transports: ['websocket'], path: '/api/socket.io' })
const M = new Roleypoly(router, io, app) // eslint-disable-line no-unused-vars
const M = new Roleypoly(io, app) // eslint-disable-line no-unused-vars
app.keys = [ process.env.APP_KEY ]

View file

@ -3,12 +3,13 @@
"version": "2.0.0",
"main": "index.js",
"scripts": {
"start": "pm2 start index.js",
"dev": "pm2 start index.js --watch",
"build": "next build"
"start": "node index.js",
"dev": "node index.js",
"build": "next build ui"
},
"dependencies": {
"@discordjs/uws": "^11.149.1",
"@primer/components": "^10.0.1",
"chalk": "^2.4.2",
"discord.js": "^11.4.2",
"dotenv": "^6.2.0",
@ -32,5 +33,12 @@
"socket.io": "^2.2.0",
"superagent": "^4.1.0",
"uuid": "^3.3.2"
},
"devDependencies": {
"babel-eslint": "^10.0.1",
"babel-plugin-transform-flow-strip-types": "^6.22.0",
"chokidar": "^2.1.2",
"flow-type": "^1.0.1",
"standard": "^12.0.1"
}
}