(options: FileServerOptions)
| 54 | } |
| 55 | |
| 56 | export function createFileServer(options: FileServerOptions): Promise<FileServerHandle> { |
| 57 | const { projectDir, compiledDir, port = 0, stripEmbeddedRuntime = true } = options; |
| 58 | |
| 59 | const headScripts = options.headScripts ?? []; |
| 60 | const bodyScripts = options.bodyScripts ?? []; |
| 61 | |
| 62 | const app = new Hono(); |
| 63 | |
| 64 | app.get("/*", (c) => { |
| 65 | let requestPath = c.req.path; |
| 66 | if (requestPath === "/") requestPath = "/index.html"; |
| 67 | |
| 68 | // Remove leading slash |
| 69 | const relativePath = requestPath.replace(/^\//, ""); |
| 70 | const compiledPath = compiledDir ? join(compiledDir, relativePath) : null; |
| 71 | const hasCompiledFile = Boolean( |
| 72 | compiledPath && existsSync(compiledPath) && statSync(compiledPath).isFile(), |
| 73 | ); |
| 74 | const filePath = hasCompiledFile ? (compiledPath as string) : join(projectDir, relativePath); |
| 75 | |
| 76 | if (!existsSync(filePath) || !statSync(filePath).isFile()) { |
| 77 | return c.text("Not found", 404); |
| 78 | } |
| 79 | |
| 80 | const ext = extname(filePath).toLowerCase(); |
| 81 | const contentType = MIME_TYPES[ext] || "application/octet-stream"; |
| 82 | |
| 83 | if (ext === ".html") { |
| 84 | const rawHtml = readFileSync(filePath, "utf-8"); |
| 85 | const html = |
| 86 | relativePath === "index.html" |
| 87 | ? injectScriptsIntoHtml(rawHtml, headScripts, bodyScripts, stripEmbeddedRuntime) |
| 88 | : rawHtml; |
| 89 | return c.text(html, 200, { "Content-Type": contentType }); |
| 90 | } |
| 91 | |
| 92 | const content = readFileSync(filePath); |
| 93 | return new Response(content, { |
| 94 | status: 200, |
| 95 | headers: { "Content-Type": contentType }, |
| 96 | }); |
| 97 | }); |
| 98 | |
| 99 | return new Promise((resolve) => { |
| 100 | const server = serve({ fetch: app.fetch, port }, (info) => { |
| 101 | const actualPort = info.port; |
| 102 | const url = `http://localhost:${actualPort}`; |
| 103 | resolve({ |
| 104 | url, |
| 105 | port: actualPort, |
| 106 | close: () => server.close(), |
| 107 | }); |
| 108 | }); |
| 109 | }); |
| 110 | } |
no test coverage detected