import fs from 'fs'
import path from 'path'
import http from 'http'
import getPort from 'get-port'
import sirv from 'sirv'
import chokidar from 'chokidar'
import mime from 'mime-types'
import toRegExp from 'regexparam'
import { timer } from './timer'
import * as logger from './log'
import { default404 } from './default404'
import { requestToEvent } from './requestToEvent'
import { sendServerlessResponse } from './sendServerlessResponse'
import { AWS, Presta } from './types'
const style = [
'position: fixed',
'bottom: 24px',
'right: 24px',
'width: 32px',
'height: 32px',
'border-radius: 32px',
'background: white',
'color: #FF7A93',
'font-size: 20px',
'font-weight: bold',
'text-align: center',
'line-height: 31px',
'box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.04), 0px 4px 8px rgba(0, 0, 0, 0.04), 0px 16px 24px rgba(0, 0, 0, 0.04), 0px 24px 32px rgba(0, 0, 0, 0.04)',
]
const devServerIcon = `
~
`
function resolveHTML(dir: string, url: string) {
let file = path.join(dir, url)
// if no extension, it's probably intended to be an HTML file
if (!path.extname(url)) {
try {
return fs.readFileSync(path.join(dir, url, 'index.html'), 'utf8')
} catch (e) {}
}
return fs.readFileSync(file, 'utf8')
}
function createDevClient({ port }: { port: number }) {
return `
`
}
export function createServerHandler({ port, config }: { port: number; config: Presta }) {
const devClient = createDevClient({ port })
const staticDir = config.staticOutputDir
const assetDir = config.assets
return async function serveHandler(req: http.IncomingMessage, res: http.ServerResponse) {
const time = timer()
const url = req.url as string
/*
* If this is an asset other than HTML files, just serve it
*/
logger.debug({
label: 'debug',
message: `attempting to serve user static asset ${url}`,
})
/*
* first check the vcs-tracked static folder,
* then check the presta-built static folder
*
* @see https://github.com/sure-thing/presta/issues/30
*/
sirv(assetDir, { dev: true })(req, res, () => {
logger.debug({
label: 'debug',
message: `attempting to serve generated static asset ${url}`,
})
sirv(staticDir, { dev: true })(req, res, async () => {
try {
/*
* No asset file, no static file, try dynamic
*/
delete require.cache[config.functionsManifest]
const manifest = require(config.functionsManifest)
const routes = Object.keys(manifest)
const lambdaFilepath = routes
.map((route) => ({
matcher: toRegExp(route),
route,
}))
.filter(({ matcher }) => {
return matcher.pattern.test(url.split('?')[0])
})
.map(({ route }) => manifest[route])[0]
/**
* If we have a serverless function, delegate to it, otherwise 404
*/
if (lambdaFilepath) {
logger.debug({
label: 'debug',
message: `attempting to render lambda for ${url}`,
})
const { handler }: { handler: AWS['Handler'] } = require(lambdaFilepath)
const event = await requestToEvent(req)
const response = await handler(event, {})
const headers = response.headers || {}
const redir = response.statusCode > 299 && response.statusCode < 399
// get mime type
const type = headers['Content-Type'] as string
const ext = type ? mime.extension(type) : 'html'
logger.info({
label: 'serve',
message: `${response.statusCode} ${redir ? headers.Location : url}`,
duration: time(),
})
sendServerlessResponse(res, {
statusCode: response.statusCode,
headers: response.headers,
multiValueHeaders: response.multiValueHeaders,
// only html can be live-reloaded, duh
body:
ext === 'html' ? (response.body || '').split('