sharyn
Version:
Combines all the other packages under one.
173 lines (144 loc) • 4.73 kB
Flow
// @flow
/* eslint-disable import/no-extraneous-dependencies, import/no-dynamic-require, global-require */
import colors from 'colors/safe'
import exitHook from 'exit-hook'
import {
NODE_ENV,
PORT,
TESTING_PORT,
IS_TEST_ENV,
IS_LOCAL_ENV_TYPE,
ENV_TYPE,
SESSION_SECRET_KEY,
// flow-disable-next-line
} from '@sharyn/env'
import {
appRoot,
hasFile,
hasPackage,
requireCascadeFromSource,
pathCascade,
requireSharyn,
// flow-disable-next-line
} from '@sharyn/check-setup'
// flow-disable-next-line
const Koa = hasPackage('koa', true) && require(`${appRoot}/node_modules/koa`)
// flow-disable-next-line
const Router = hasPackage('koa-router', true) && require(`${appRoot}/node_modules/koa-router`)
const router = new Router()
const PREFIX = colors.cyan('[sharyn/koa]')
export const DEFAULT_PORT = 8020
export const DEFAULT_TESTING_PORT = 8021
const port = IS_TEST_ENV ? TESTING_PORT || DEFAULT_TESTING_PORT : PORT || DEFAULT_PORT
const hasDocker = hasFile('docker-compose.yml')
let server
const stopServer_ = (options?: Object) => {
if (server) {
if (!(options?.silent || IS_TEST_ENV)) {
// eslint-disable-next-line no-console
console.log() // cross-os newline
// eslint-disable-next-line no-console
console.log(`${PREFIX} Server stopped`)
}
const sharynDb = requireSharyn('db')
sharynDb && sharynDb.knex.destroy()
const sharynRedis = hasDocker && requireSharyn('redis')
sharynRedis && sharynRedis.quit()
return server.close()
}
throw Error('Tried to stop the server but no server was running')
}
const startServer_ = (manualRouting: Function, options?: Object) => {
const routing =
manualRouting || requireCascadeFromSource('_server/routing.js', 'server/routing.js')
if (!routing) {
throw Error(
'You must pass a routing function to startServer, or have a _server/routing.js file exporting the routing function',
)
}
if (!(options?.silent || IS_TEST_ENV)) {
// eslint-disable-next-line no-console
console.log(
`\n${PREFIX} 🌹 Server running on PORT: ${port} | NODE_ENV: ${NODE_ENV} | ENV_TYPE: ${ENV_TYPE}`,
)
}
exitHook(() => stopServer_())
const app = new Koa()
if (hasPackage('koa-session')) {
app.keys = [SESSION_SECRET_KEY]
}
app.use(async (ctx, next) => {
try {
await next()
} catch (err) {
ctx.status = err.status || 500
ctx.redirect('/error')
ctx.app.emit('error', err, ctx)
}
})
if (hasPackage('koa-sslify')) {
// flow-disable-next-line
const enforceHttps = require('koa-sslify')
const hasHeroku = hasFile('Procfile')
IS_LOCAL_ENV_TYPE || app.use(enforceHttps({ trustProtoHeader: hasHeroku }))
}
if (hasPackage('koa-session')) {
// flow-disable-next-line
const session = require('koa-session')
const sessionOptions: Object = {
maxAge: 1000 * 60 * 60 * 24 * 14, // 2 weeks
rolling: true,
}
const sharynRedis = hasDocker && requireSharyn('redis')
if (sharynRedis) {
sessionOptions.store = {
get: async key => JSON.parse(await sharynRedis.getAsync(`session:${key}`)),
set: (key, sess) => sharynRedis.setAsync(`session:${key}`, JSON.stringify(sess)),
destroy: key => sharynRedis.delAsync(key),
}
}
app.use(session(sessionOptions, app))
}
if (hasPackage('koa-body')) {
// flow-disable-next-line
app.use(require('koa-body')({ multipart: true }))
}
if (hasPackage('koa-compress')) {
// flow-disable-next-line
app.use(require('koa-compress')())
}
if (hasPackage('koa-mount') && hasPackage('koa-static')) {
// flow-disable-next-line
const mount = require('koa-mount')
// flow-disable-next-line
const serveStatic = require('koa-static')
app
.use(mount('/static', serveStatic('dist')))
.use(mount('/static', serveStatic('public')))
.use(mount('/', serveStatic('public/root')))
}
if (hasPackage('koa-favicon')) {
app.use(
// flow-disable-next-line
require('koa-favicon')(
`./${pathCascade(
'public/img/favicon/favicon.ico',
'public/img/favicon.ico',
'public/favicon.ico',
)}`,
),
)
}
if (hasPackage('apollo-server-koa')) {
// flow-disable-next-line
const { ApolloServer } = require('apollo-server-koa')
const apolloServer = new ApolloServer(options?.apolloConfig ?? {})
apolloServer.applyMiddleware({ app })
}
routing(router)
app.use(router.routes()).use(router.allowedMethods())
app.on('error', err => console.error(err))
server = app.listen(options?.port || port)
}
export const startServer = startServer_
export const stopServer = stopServer_