stoneware

Documentation

Routing

File-based, Next.js-style conventions resolved by Bun's own router.

Routes map from the filesystem using the conventions most developers already know. Path resolution is delegated to Bun.FileSystemRouter rather than reimplemented.

routes/txt
routes/index.tsx          ->  /
routes/about.tsx          ->  /about
routes/blog/[slug].tsx    ->  /blog/:slug
routes/api/subscribe.ts   ->  /api/subscribe

Pages and actions

A module that default-exports a component is a page. A module that exports HTTP method handlers is a server action. Nothing else distinguishes them — there is no config file listing routes.

routes/blog/[slug].tsxtsx
import type { PageProps } from "stoneware";
import { getPost } from "../../lib/posts.ts";

export default function Post({ params }: PageProps) {
  const post = getPost(params.slug);
  if (!post) return <h1>Not found</h1>;

  return (
    <article>
      <h1>{post.title}</h1>
      <time datetime={post.date}>{post.date}</time>
    </article>
  );
}

Params arrive percent-decoded and are escaped like any other value when interpolated, so a slug containing markup is inert.

Something wrong in the framework itself rather than the page? Open an issue on GitHub.