Last active
May 4, 2021 15:16
-
-
Save jsjoeio/f1695355e44b0a90bb17619f2faf1016 to your computer and use it in GitHub Desktop.
oak - example static server which checks for HTML files with same name as directory for Next.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* This is an example of a server that will serve static content out of the | |
* $CWD/examples/static path. | |
*/ | |
import { | |
bold, | |
cyan, | |
green, | |
red, | |
yellow, | |
} from "https://deno.land/[email protected]/fmt/colors.ts" | |
import { extname } from "https://deno.land/[email protected]/path/mod.ts" | |
import { Application, HttpError, Status } from "https://deno.land/x/oak/mod.ts" | |
const app = new Application() | |
// Error handler middleware | |
app.use(async (context, next) => { | |
try { | |
await next() | |
} catch (e) { | |
if (e instanceof HttpError) { | |
// deno-lint-ignore no-explicit-any | |
context.response.status = e.status as any | |
if (e.expose) { | |
context.response.body = `<!DOCTYPE html> | |
<html> | |
<body> | |
<h1>${e.status} - ${e.message}</h1> | |
</body> | |
</html>` | |
} else { | |
context.response.body = `<!DOCTYPE html> | |
<html> | |
<body> | |
<h1>${e.status} - ${Status[e.status]}</h1> | |
</body> | |
</html>` | |
} | |
} else if (e instanceof Error) { | |
context.response.status = 500 | |
context.response.body = `<!DOCTYPE html> | |
<html> | |
<body> | |
<h1>500 - Internal Server Error</h1> | |
</body> | |
</html>` | |
console.log("Unhandled Error:", red(bold(e.message))) | |
console.log(e.stack) | |
} | |
} | |
}) | |
// Logger | |
app.use(async (context, next) => { | |
await next() | |
const rt = context.response.headers.get("X-Response-Time") | |
console.log( | |
`${green(context.request.method)} ${cyan( | |
context.request.url.pathname | |
)} - ${bold(String(rt))}` | |
) | |
}) | |
// Response Time | |
app.use(async (context, next) => { | |
const start = Date.now() | |
await next() | |
const ms = Date.now() - start | |
context.response.headers.set("X-Response-Time", `${ms}ms`) | |
}) | |
// Send static content | |
app.use(async (context) => { | |
const root = `${Deno.cwd()}/examples/static` | |
const requestPath = context.request.url.pathname | |
const fullFilePath = `${root}${requestPath}` | |
const path = await handleFileToServe(requestPath, root) | |
await context.send({ | |
root, | |
path, | |
index: "index.html", | |
}) | |
}) | |
app.addEventListener("listen", ({ hostname, port, serverType }) => { | |
console.log(bold("Start listening on ") + yellow(`${hostname}:${port}`)) | |
console.log(bold(" using HTTP server: " + yellow(serverType))) | |
}) | |
await app.listen({ hostname: "127.0.0.1", port: 8000 }) | |
async function isDirectory(path: string) { | |
const fileInfo = await Deno.stat(path) | |
return fileInfo.isDirectory | |
} | |
async function hasHtmlFileForDir(fileName: string, parentDir: string) { | |
let hasHtmlFile = false | |
// Source: https://deno.land/[email protected]/http/file_server.ts#L167 | |
for await (const entry of Deno.readDir(parentDir)) { | |
if (entry.name === `${fileName}.html` && entry.isFile) { | |
hasHtmlFile = true | |
break | |
} | |
} | |
return hasHtmlFile | |
} | |
async function handleFileToServe(path: string, root: string) { | |
if (path === "/") { | |
return `index.html` | |
} | |
const fileExt = extname(path) | |
const fullFilePath = `${root}${path}` | |
if (fileExt === "" && (await isDirectory(fullFilePath))) { | |
console.log("looks promising") | |
// TODO this only looks one level deep | |
const fileName = path.substr(1) | |
const parentDir = getParentDir(fullFilePath) | |
const hasHtmlFile = await hasHtmlFileForDir(fileName, parentDir) | |
console.log(`hasHtmlFile: ${hasHtmlFile}`) | |
if (hasHtmlFile) { | |
return `${path}.html` | |
} | |
} | |
return path | |
} | |
function getParentDir(path: string) { | |
// /Users/jp/Dev/testing/oak-server/examples/static/course | |
// Source: https://stackoverflow.com/a/16863827/3015595 | |
return path.substring(0, path.lastIndexOf("/")) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment