The minimalist Bun web framework.

WaveKit is a tiny framework built on top of Bun HTTP. Bleeding edge.

Features

Getting started

The kit is a web server library. Use it like:

Install

bun add @wavekit/wave @wavekit/kit

Nightly release:

bun add https://pkg.pr.new/getgrinta/wavekit/wave@main https://pkg.pr.new/getgrinta/wavekit/kit@main

Usage

// src/index.ts
import { createWaveKit } from "@wavekit/kit"

createWaveKit().then(({ routes }) => {
	console.log("Serving on http://localhost:3000")
	Bun.serve({ port: 3000, routes })
})
// app/index.ts
import { wave } from "@wavekit/wave";
import type { WaveKitHandler } from "@wavekit/kit";

export const GET: WaveKitHandler = (c) => {
	return c.html(
		wave.article({ class: "container mx-auto" }, (article) => {
			article
				.h1("WaveKit is awesome.")
				.p("Write your templates with lightweight engine (<150 LOC).")
				.p("Create templates without separate JSX and TSX files.")
		})
	)
}

🌊 Wave

Wave is a lightweight templating engine built on top of Bun. You can just do things.

// src/components/form.tsx
import { wave } from "@wavekit/wave";

export const SignUpForm = wave.form({
	method: "POST",
	action: "/api/sign-up",
	class: "flex flex-col gap-2",
}, (signUpForm) => {
	signUpForm
		.h1("Sign Up")
		.label({ for: "usernameField", class: "label" }, "Username")
		.input({ id: "usernameField", name: "username", required: true, class: "input" })
		.label({ for: "emailField", class: "label" }, "Email")
		.input({ id: "emailField", name: "email", type: "email", required: true, class: "input" })
		.label({ for: "passwordField", class: "label" }, "Password")
		.input({ id: "passwordField", name: "password", type: "password", required: true, class: "input" })
		.label({ for: "termsField", class: "label" }, "I agree to the terms")
		.input({ type: "checkbox", name: "terms", required: true, class: "checkbox" })
		.button({ type: "submit", class: "btn btn-primary" }, "Sign Up");
})

🧰 Kit

Kit is a web server library. Use it like:

// src/index.ts
import { createWaveKit, ssgRender, type WaveKitHooks } from "@wavekit/kit";
import { findUserByToken } from "./src/auth";

const hooks: WaveKitHooks = {
	async beforeHandler(c) {
		const bearerToken = c.req.headers.get("Authorization")?.split(" ")?.[1];
		if (!bearerToken) {
			return c.json({ error: "Unauthorized" }, 401);
		}
		const user = await findUserByToken(bearerToken);
		if (!user) {
			return c.json({ error: "Unauthorized" }, 401);
		}
		c.store.set("user", user);
	},
};

// Option 1: For serving
createWaveKit({ hooks }).then(({ routes }) => {
	console.log("Serving on http://localhost:3000");
	Bun.serve({
		port: 3000,
		routes,
		development: process.env.NODE_ENV === "development",
	});
});

// Option 2: For static generation
ssgRender()