【BUN】静态托管服务
index.ts
// index.ts
import type {Serve} from "bun"
import {stat, readdir} from 'node:fs/promises'
import ejs from 'ejs'
interface Dir {
url: string,
type: 'dir' | 'back' | 'file' | 'unknown',
path: string,
name: string
}
const BASEURL = '/public' // 托管项目下public文件夹
const promiseAwait = <T>(promise: Promise<T>) => {
return promise.then(v => [null, v] as const).catch(e => [e, null] as const)
}
//构建dir目录
const buildDir = async (dir: string, pathname: string) => {
const arr: Array<Dir> = []
const files = await readdir(dir)
if (pathname !== '/') {
arr.push({
url: dir,
type: 'back',
name: '../',
path: `javascript:history.back()`
})
}
for await (const file of files) {
const url = `${dir}/${file}`
const [, where] = await promiseAwait(stat(url))
if (!where) continue
const isDir = where.isDirectory()
const isFile = where.isFile()
arr.push({
url,
type: isDir ? 'dir' : isFile ? 'file' : 'unknown',
name: file,
path: `${pathname === '/' ? '' : pathname}/${file}`
})
}
return arr
}
// Bun 托管静态文件
const server: Serve = {
async fetch(req) {
const pathname = new URL(req.url).pathname
const path = `${process.cwd()}${BASEURL}/${pathname}`
// 判断是文件还是目录
const [error, where] = await promiseAwait(stat(path))
if (!where) {
return new Response(error)
}
const isDir = where.isDirectory()
if (isDir) {
const dirs = await buildDir(path, pathname)
const html = await ejs.renderFile(`${import.meta.dir}/dir.ejs`, {dirs})
return new Response(html, {
headers: {
'Content-Type': 'text/html'
}
})
}
const isFile = where.isFile()
if (isFile) {
const file = Bun.file(path)
const exists = await file.exists()
if (exists) return new Response(file)
}
return new Response(null, {status: 404})
}
}
export default server
dir.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Directory</title>
<style>
li {
padding: 6px;
}
li.dir::marker {
content: '📁';
}
li.file::marker {
content: '📄';
}
li.back::marker {
content: '🔙';
}
</style>
</head>
<body>
<ul>
<% for (let i = 0; i < dirs.length; i++) { %>
<% const item = dirs[i] %>
<li class="<%= item.type %>">
<a href="<%= item.path %>">
<%= item.name %>
</a>
</li>
<% } %>
</ul>
</body>
</html>
usage
bun ./index.ts
example
为之则易,不为则难。