| src | ||
| .gitignore | ||
| bun.lock | ||
| CLAUDE.md | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
hype
░▒▓███████████████████████████████████████████████▓▒░
░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓███████▓▒░░▒▓████████▓▒░
░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░
░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░
░▒▓████████▓▒░░▒▓██████▓▒░░▒▓███████▓▒░░▒▓██████▓▒░
░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░
░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░
░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓████████▓▒░
░▒▓███████████████████████████████████████████████▓▒░
hype wraps hono with useful defaults:
- HTTP logging (disable with
NO_HTTP_LOGenv variable) - Static files served from
pub/ - Page-based routing to
.tsxfiles that export aJSXfunction in./src/pages - Transpile
.tsfiles insrc/js/blah.tsviawebsite.com/js/blah.ts
Overview
Your project structure should be:
.
├── README.md
├── package.json
├── pub
│ ├── asset.txt
│ └── img
│ └── logo.png
├── src
│ ├── css
│ │ └── main.css
│ ├── js
│ │ ├── about.ts
│ │ └── main.ts
│ ├── shared
│ │ └── utils.ts
│ ├── pages
│ │ ├── _layout.tsx
│ │ ├── about.tsx
│ │ └── index.tsx
│ └── server.tsx
└── 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.
Here's a starting point:
export default ({ children, title }: any) => (
<html lang="en">
<head>
<title>{title ?? "hype"}</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link href="/css/main.css" rel="stylesheet" />
<script src="/js/main.ts" type="module"></script>
</head>
<body>
<main>{children}</main>
</body>
</html>
)
css
CSS can be accessed via /css/main.css:
<link href="/css/main.css" rel="stylesheet" />
Or written inline using the css template tag:
import { css } from "hype"
export default () => (
<div>
{css`
* {
color: red;
}
`}
<h1>Hello</h1>
</div>
)
css reset
hype includes a css reset for your convenience:
<link href="/css/reset.css" rel="stylesheet" />
js
JS can be accessed (and transpiled) via /js/main.ts or /shared/utils.ts:
<script src="/js/main.ts" type="module"></script>
import your modules relatively, for example in main.ts:
import { initAbout } from "./about"
import utils from "./shared/utils"
Or written inline as transpiled typescript using the js template tag:
import { js } from "hype"
export default () => (
<div>
{js`
window.onload = () => alert(welcomeMsg(Date.now()))
function welcomeMsg(time: number): string {
return "Welcome to my website!"
}
`}
<h1>Hello!</h1>
</div>
)
pub
Anything in pub/ is served as-is. Simple stuff.
utils
hype includes helpful utils for your webapp:
capitalize(str: string): string- Capitalizes a wordcssTemplate Tag - Lets you inline CSS in your TSX. Returns a<style>tagdarkenColor(hex: string, opacity: number): string- Darken a hex color by blending with black. opacity 1 = original, 0 = blackisDarkMode(): boolean- Check if the user prefers dark modejsTemplate Tag - Lets you inline JavaScript in your TSX. Transpiles and returns a<script>taglightenColor(hex: string, opacity: number): string- Lighten a hex color by blending with white. opacity 1 = original, 0 = whiterand(end = 2, startAtZero = false): number- Generate random integer.rand(2)flips a coin,rand(6)rolls a die,rand(20)rolls d20randIndex<T>(list: T[]): number | undefined- Get a random index from an array.randIndex([5, 7, 9])returns0,1, or2randItem<T>(list: T[]): T | undefined- Get a random item from an array.randItem([5, 7, 9])returns5,7, or9randomId(): string- Generate a 6 character random IDrandRange(start = 0, end = 12): number- Generate random integer in range.randRange(1, 6)rolls a dieredirectBack(c: Context, fallback = "/"): Response- Redirect to the referrer, or fallback if no referrertimes(n: number): number[]- Generate array of integers.times(3)returns[1, 2, 3]transpile(path: string): Promise<string>- Transpile a TypeScript file atpathto JavaScript (cached by mtime)unique<T>(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
- Add
devandstarttopackage.json:
"scripts": {
"start": "bun run src/server.tsx",
"dev": "bun run --hot src/server.tsx"
},
- Use our
tsconfig.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/*"]
}
}
}
- Use
Hypejust likeHonoin yourserver.tsx, exportingapp.defaults:
import { Hype } from "hype"
const app = new Hype()
app.get("/my-custom-routes", (c) => c.text("wild, wild stuff"))
export default app.defaults
- Enter dev mode
bun install
bun test