it's alive
This commit is contained in:
parent
465ed69fc3
commit
45286920de
|
|
@ -1,7 +1,7 @@
|
|||
import { text } from "./other"
|
||||
import { css } from "@utils"
|
||||
|
||||
export default (c: Context) => {
|
||||
export default () => {
|
||||
return <>
|
||||
{css`
|
||||
body {
|
||||
|
|
|
|||
29
nose/app/routes.tsx
Normal file
29
nose/app/routes.tsx
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import { routes } from "@utils"
|
||||
|
||||
export default routes({
|
||||
"GET /": index,
|
||||
"GET /pets": pets
|
||||
})
|
||||
|
||||
function index() {
|
||||
return <>
|
||||
<h1>Hi world!</h1>
|
||||
<p>Welcome to my personal web page.</p>
|
||||
<p>If you are looking for information on pets, click here:</p>
|
||||
<p><a href="/pets">PETS</a></p>
|
||||
</>
|
||||
}
|
||||
|
||||
function pets(c: Context) {
|
||||
return c.html(<>
|
||||
<ul>
|
||||
<li>dogs</li>
|
||||
<li>cats</li>
|
||||
<li>iguanas</li>
|
||||
<li>hamsters</li>
|
||||
<li>snakes</li>
|
||||
<li>chickens</li>
|
||||
<li>...even goats!</li>
|
||||
</ul>
|
||||
</>)
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"name": "pluto",
|
||||
"module": "index.ts",
|
||||
"module": "src/server.tsx",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "bun src/server.ts",
|
||||
"dev": "bun --hot src/server.ts"
|
||||
"start": "bun src/server.tsx",
|
||||
"dev": "bun --hot src/server.tsx"
|
||||
},
|
||||
"alias": {
|
||||
"@utils": "./src/utils.tsx",
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import color from "kleur"
|
|||
|
||||
import { NOSE_ICON, NOSE_DIR, NOSE_BIN, NOSE_APP } from "./config"
|
||||
import { transpile, isFile } from "./utils"
|
||||
import { serveApp } from "./webapp"
|
||||
import { apps, serveApp } from "./webapp"
|
||||
|
||||
//
|
||||
// Hono setup
|
||||
|
|
@ -43,12 +43,29 @@ app.get("/js/:path{.+}", async c => {
|
|||
// app routes
|
||||
//
|
||||
|
||||
app.get("*", async c => {
|
||||
app.use("*", async (c, next) => {
|
||||
const url = new URL(c.req.url)
|
||||
const domains = url.hostname.split(".")
|
||||
const subdomain = domains.length > 1 ? domains[0]! : "none"
|
||||
const subdomain = domains.length > 1 ? domains[0]! : ""
|
||||
|
||||
return await serveApp(c, subdomain)
|
||||
if (subdomain) {
|
||||
const app = serveApp(c, subdomain)
|
||||
return await app
|
||||
}
|
||||
|
||||
return next()
|
||||
})
|
||||
|
||||
app.get("/", c => {
|
||||
const url = new URL(c.req.url)
|
||||
const domain = url.hostname
|
||||
const port = url.port
|
||||
|
||||
return c.html(<>
|
||||
<h1>apps</h1>
|
||||
<ul>{apps().map(app => <li><a href={`http://${app}.${domain}:${port}`}>{app}</a></li>)}
|
||||
</ul>
|
||||
</>)
|
||||
})
|
||||
|
||||
//
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
import { Hono } from "hono"
|
||||
import { statSync } from "node:fs"
|
||||
import { stat } from "node:fs/promises"
|
||||
import { type Handler, toResponse } from "./webapp"
|
||||
|
||||
// Is the given `path` a file?
|
||||
export function isFile(path: string): boolean {
|
||||
|
|
@ -26,7 +28,6 @@ export function randomID(): string {
|
|||
return Math.random().toString(36).slice(2, 10)
|
||||
}
|
||||
|
||||
|
||||
const transpiler = new Bun.Transpiler({ loader: 'tsx' })
|
||||
const transpileCache: Record<string, string> = {}
|
||||
|
||||
|
|
@ -65,3 +66,25 @@ export function js(strings: TemplateStringsArray, ...values: any[]) {
|
|||
}, '')
|
||||
}} />
|
||||
}
|
||||
|
||||
// for defining routes in your NOSE webapp
|
||||
// example:
|
||||
// export default routes({
|
||||
// "GET /": index,
|
||||
// "GET /pets": pets
|
||||
// })
|
||||
export function routes(def: Record<string, Handler>): Hono {
|
||||
const app = new Hono
|
||||
|
||||
for (const key in def) {
|
||||
const parts = key.split(" ") // GET /path
|
||||
const method = parts[0] || "GET"
|
||||
const path = parts[1] || "/"
|
||||
|
||||
console.log(method, path, def[key])
|
||||
//@ts-ignore
|
||||
app.on(method, path, async c => toResponse(await def[key](c)))
|
||||
}
|
||||
|
||||
return app
|
||||
}
|
||||
|
|
@ -1,18 +1,32 @@
|
|||
import type { Context } from "hono"
|
||||
import { type Context, Hono } from "hono"
|
||||
import type { Child } from "hono/jsx"
|
||||
import { renderToString } from "hono/jsx/dom/server"
|
||||
import { join } from "node:path"
|
||||
import { readdirSync } from "node:fs"
|
||||
import { NOSE_APP } from "./config"
|
||||
import { isFile } from "./utils"
|
||||
|
||||
type App = (r: Context) => string | Child | Response
|
||||
export type Handler = (r: Context) => string | Child | Response | Promise<Response>
|
||||
export type App = Hono | Handler
|
||||
|
||||
export async function serveApp(c: Context, subdomain: string): Promise<Response> {
|
||||
const app = await findApp(subdomain)
|
||||
|
||||
if (app)
|
||||
return await toResponse(app(c))
|
||||
if (!app) return c.text(`App Not Found: ${subdomain}`, 404)
|
||||
|
||||
return c.text(`App Not Found: ${subdomain}`, 404)
|
||||
if (app instanceof Hono)
|
||||
return app.fetch(c.req.raw)
|
||||
else
|
||||
return toResponse(app(c))
|
||||
}
|
||||
|
||||
export function apps(): string[] {
|
||||
const apps: string[] = []
|
||||
|
||||
for (const entry of readdirSync(NOSE_APP))
|
||||
apps.push(entry.replace(/\.tsx?/, ""))
|
||||
|
||||
return apps
|
||||
}
|
||||
|
||||
async function findApp(name: string): Promise<App | undefined> {
|
||||
|
|
@ -43,13 +57,13 @@ async function loadApp(path: string): Promise<App | undefined> {
|
|||
return mod.default as App
|
||||
}
|
||||
|
||||
async function toResponse(source: string | Child | Response): Promise<Response> {
|
||||
export function toResponse(source: string | Child | Response): Response {
|
||||
if (source instanceof Response)
|
||||
return source
|
||||
else if (typeof source === "string")
|
||||
return new Response(source)
|
||||
else
|
||||
return new Response(await source?.toString(), {
|
||||
return new Response(renderToString(source), {
|
||||
headers: {
|
||||
"Content-Type": "text/html; charset=utf-8"
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user