# 🎪 hype ░▒▓███████████████████████████████████████████████▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓███████▓▒░░▒▓████████▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓████████▓▒░░▒▓██████▓▒░░▒▓███████▓▒░░▒▓██████▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓████████▓▒░ ░▒▓███████████████████████████████████████████████▓▒░ `hype` wraps `hono` with useful features for fast prototyping: - HTTP logging to the console (disable with `NO_HTTP_LOG` env variable) - Auto-port selection in dev mode: if the port is busy, tries the next one (disable with `NO_AUTOPORT` env variable) - Static files served from `pub/` - Page-based routing to `.tsx` files that export a `JSX` function in `./src/pages` - Transpile `.ts` files in `src/client/blah.ts` via `website.com/client/blah.ts` - Default, simple HTML5 layout with working frontend transpilation/bundling, or supply your own. - Optional CSS reset. - Optional pico.css. ## Overview Your project structure should be: ``` . ├── README.md ├── package.json ├── pub │   ├── asset.txt │   └── img │   └── logo.png ├── src │   ├── css │   │   └── main.css │   ├── client │   │   ├── about.ts │   │   └── main.ts │   ├── shared │   │   └── utils.ts │   ├── pages │   │   ├── _layout.tsx │   │   ├── about.tsx │   │   └── index.tsx │   └── server │   └── index.ts └── tsconfig.json ``` ### URLs In the above, `/about` will render `./src/pages/about.tsx`. The `req` JSX prop will be given the `Hono` request: export default ({ req }) => `Query Param 'id': ${req.query('id')}` To put a file in `./src/pages` but prevent it from being server, preface it with `_`. ### Layout `hype` will wrap everything in a simple default layout unless `./src/pages/_layout.tsx` exists, in which case it'll use the default export in that file. You can also create hype with `new Hype({ layout: false })` to disable Hype's default. Using the default layout, you can put TS in `./src/client/main.ts` and css in `./src/css/main.css`. They'll automatically work in your app. Here's a starting point: ```tsx export default ({ children, title }: any) => ( {title ?? "hype"}
{children}
) ``` ### pico.css To use pico.css with the default layout, create `Hype` with `{ pico: true }`: ```typescript import { Hype } from "hype" const app = new Hype({ pico: true }) ``` You can also use pico in your custom layouts: ```html ``` ### css CSS can be accessed via `/css/main.css`: ```html ``` ### css reset To use reset.css with the default layout, create `Hype` with `{ reset: true }`: ```typescript import { Hype } from "hype" const app = new Hype({ reset: true }) ``` You can also use the css reset in your custom layouts: ```html ``` ### js JS can be accessed (and transpiled) via `/client/main.ts` or `/shared/utils.ts`: ```html ``` import your modules relatively, for example in `main.ts`: ```typescript import { initAbout } from "./about" import utils from "./shared/utils" ``` ### pub Anything in `pub/` is served as-is. Simple stuff. ### Server-Sent Events (SSE) `hype` provides a simple `app.sse()` helper for streaming data to clients: ```typescript import { Hype } from "hype" const app = new Hype() // Stream current time every second app.sse('/api/time', (send) => { send({ time: Date.now() }) const interval = setInterval(() => send({ time: Date.now() }), 1000) return () => clearInterval(interval) // cleanup on disconnect }) ``` The `send()` function: - Automatically JSON.stringify's objects (strings are sent as-is) - Accepts an optional second parameter for named events: `send(data, 'eventName')` The handler can return a cleanup function that's called when the client disconnects. You also have access to the Hono context as the second parameter: ```typescript app.sse('/api/user-events', (send, c) => { const userId = c.req.query('userId') // ... subscribe to user-specific events }) ``` **Client-side usage:** ```typescript const events = new EventSource('/api/time') events.onmessage = (e) => { const data = JSON.parse(e.data) console.log('Time:', data.time) } // For named events: events.addEventListener('eventName', (e) => { console.log('Got event:', e.data) }) ``` Test with curl: ```sh curl -N http://localhost:3000/api/time ``` ### utils `hype` includes helpful utils for your webapp: - `capitalize(str: string): string` - Capitalizes a word - `darkenColor(hex: string, opacity: number): string` - Darken a hex color by blending with black. opacity 1 = original, 0 = black - `isDarkMode(): boolean` - Check if the user prefers dark mode - `lightenColor(hex: string, opacity: number): string` - Lighten a hex color by blending with white. opacity 1 = original, 0 = white - `rand(end = 2, startAtZero = false): number` - Generate random integer. `rand(2)` flips a coin, `rand(6)` rolls a die, `rand(20)` rolls d20 - `randIndex(list: T[]): number | undefined` - Get a random index from an array. `randIndex([5, 7, 9])` returns `0`, `1`, or `2` - `randItem(list: T[]): T | undefined` - Get a random item from an array. `randItem([5, 7, 9])` returns `5`, `7`, or `9` - `randomId(): string` - Generate a 6 character random ID - `randRange(start = 0, end = 12): number` - Generate random integer in range. `randRange(1, 6)` rolls a die - `redirectBack(c: Context, fallback = "/"): Response` - Redirect to the referrer, or fallback if no referrer - `times(n: number): number[]` - Generate array of integers. `times(3)` returns `[1, 2, 3]` - `transpile(path: string): Promise` - Transpile a TypeScript file at `path` to JavaScript (cached by mtime) - `unique(array: T[]): T[]` - Remove duplicates from array. `unique([1,1,2,2,3,3])` returns `[1,2,3]` - `weightedRand(): number` - Generate random number between 1 and 10 with decreasing probability (1 is most likely, 10 is least) ## Setup 0. Add the dependency to your project: ```sh bun add git+https://git.nose.space/defunkt/hype ``` 1. Add `dev` and `start` to `package.json`: ```json "scripts": { "start": "bun run src/server/index.ts", "dev": "bun run --hot src/server/index.ts" }, ``` 2. Use our `tsconfig.json`: ```json { "compilerOptions": { "lib": ["ESNext", "DOM"], "target": "ESNext", "module": "Preserve", "moduleDetection": "force", "jsx": "react-jsx", "jsxImportSource": "hono/jsx", "allowJs": true, "moduleResolution": "bundler", "allowImportingTsExtensions": true, "verbatimModuleSyntax": true, "noEmit": true, "strict": true, "skipLibCheck": true, "noFallthroughCasesInSwitch": true, "noUncheckedIndexedAccess": true, "noImplicitOverride": true, "noUnusedLocals": false, "noUnusedParameters": false, "noPropertyAccessFromIndexSignature": false, "baseUrl": ".", "paths": { "$*": ["src/server/*"], "#*": ["src/client/*"], "@*": ["src/shared/*"] } } } ``` 3. Use `Hype` just like `Hono` in your `src/server.ts`, exporting `app.defaults`: ```typescript import { Hype } from "hype" const app = new Hype() app.get("/my-custom-routes", (c) => c.text("wild, wild stuff")) export default app.defaults ``` 4. Enter dev mode ```sh bun install bun dev ```