Skip to content

JoviDeCroock/pracht

Repository files navigation

pracht — Full-stack Preact, per route.

npm version CI status

pracht

Full-stack Preact, per route. (pracht /praxt/ — Dutch & German for splendor. Also: how you've always mispronounced Preact.)

Pick SPA, SSR, SSG, or ISG on a route-by-route basis. Ship less JavaScript by default. Deploy the same codebase to Node, Cloudflare, or Vercel.

npm create pracht@latest my-app

Documentation · Why pracht · Getting started · Compare to other frameworks

Why pracht

  • Preact-first — the low bundle size that you know and love with a familiar API.
  • Per-route render modes — SPA, SSR, SSG, and ISG in the same app. No global default fighting you.
  • Explicit over magic — a typed defineApp() manifest wires routes, shells, and middleware. What runs where is never a mystery. Prefer file-based routing? Opt in to the pages router and skip the manifest entirely.
  • Vite-native — instant HMR, fast builds, multi-environment output out of the box.
  • Performance budgets built inpracht build --analyze reports per-route client JS (gzip + raw), and per-route budgets fail the build when a route ships too much.
  • Deploy anywhere — one codebase, one build, three production-ready adapters (Node, Cloudflare Workers, Vercel).
  • Env safety built in — typed serverEnv/publicEnv helpers with a PRACHT_PUBLIC_ prefix rule, and builds fail when client bundles reference non-public env vars.

At a glance

Two routing styles, your choice:

Manifest routing — full control, explicit wiring:

// src/routes.ts
import { defineApp, group, route, timeRevalidate } from "@pracht/core";

export const app = defineApp({
  shells: {
    app: () => import("./shells/app.tsx"),
    public: () => import("./shells/public.tsx"),
  },
  middleware: {
    auth: () => import("./middleware/auth.ts"),
  },
  routes: [
    group({ shell: "public" }, [
      route("/", () => import("./routes/home.tsx"), { render: "ssg" }),
      route("/pricing", () => import("./routes/pricing.tsx"), {
        render: "isg",
        revalidate: timeRevalidate(3600),
      }),
    ]),
    group({ shell: "app", middleware: ["auth"] }, [
      route("/dashboard", () => import("./routes/dashboard.tsx"), { render: "ssr" }),
      route("/settings", () => import("./routes/settings.tsx"), { render: "spa" }),
    ]),
  ],
});

One manifest. Four render strategies. No renaming folders to change behavior.

Pages router — file-based, zero manifest:

// vite.config.ts
export default defineConfig({
  plugins: [pracht({ pagesDir: "/src/pages", adapter: nodeAdapter() })],
});
src/pages/
  index.tsx        → /
  blog/[slug].tsx  → /blog/:slug

Same render modes, same adapters — just let the filesystem drive.

Create an app

npm create pracht@latest my-app

The prompts cover the target directory, hosting adapter (Node.js, Cloudflare Workers, Vercel), router (manifest or pages), and optional Tailwind CSS. For non-interactive runs pass flags instead — e.g. --template=tailwind (or --template=minimal), --adapter=node, --no-git, --yes. See packages/start/README.md for the full list.

The starter gives you:

  • pracht dev — local SSR + HMR, a /_pracht devtools page with the resolved route/API graph (JSON at /_pracht.json), and Server-Timing middleware/loader/render phase timings on every dev SSR response
  • pracht build — client/server output plus SSG/ISG prerendering, with --analyze for a per-route client JS report and budget enforcement
  • pracht preview — build and serve the production build locally
  • pracht inspect [routes|api|build] --json — resolved app graph metadata
  • pracht generate route|shell|middleware|api — framework-native scaffolding; generate route also emits a Playwright smoke test when the app has an e2e setup
  • pracht verify — fast framework-aware checks with --changed and --json, including defineApp({ constraints }) enforcement and app-graph snapshot freshness
  • pracht plan — semantic app-graph diff against a base git ref (--write refreshes the committed .pracht/app-graph.json snapshot; --markdown for PR comments)
  • pracht report — PR-ready markdown assembled from the graph diff, verify results, and bundle budgets
  • pracht doctor — app wiring checks with optional JSON output
  • Optional Tailwind CSS wiring, a git repo with an initial commit, and (for the Node adapter) a multi-stage Dockerfile

AI-assisted development

Pracht is built to be operated by coding agents as much as by humans — and for the humans reviewing what agents produce:

  • Provable changes — a committed app-graph snapshot (.pracht/app-graph.json) plus pracht plan gives reviewers an intent-level diff of routes, render modes, shells, middleware, and API endpoints; pracht report turns it into the factual half of a PR description. See docs/AGENT_WORKFLOW.md.
  • Machine-enforced invariantsdefineApp({ constraints }) declares rules like requireMiddleware("/app/**", "auth") that pracht verify enforces deterministically, so no author (human or LLM) can merge a violation.
  • MCP serverpracht mcp starts a stdio Model Context Protocol server so agents can natively inspect the resolved app graph, run doctor/verify diagnostics, diff and snapshot the graph (plan/report), read the authoring guide (get_docs), and scaffold routes, shells, middleware, and API handlers. See docs/MCP.md for registration and the tool reference.
  • Authoring guide for agentspracht llms --write drops the framework's conventions into llms.txt so any coding agent picks them up.
  • Claude Code skills — 28 skills for scaffolding, auditing, testing, debugging, and deploying pracht apps live in skills/. See the agent skills section below.

Agent skills

The skills are distributed three ways (see the catalog):

  • Discovery endpoint — every skill is published at https://pracht.resynapse.dev/skills/<name>/SKILL.md, listed with SHA-256 digests in the manifest at /.well-known/agent-skills/index.json and advertised via a Link: rel="agent-skills" header.
  • create-prachtnpm create pracht@latest seeds the full catalog into new apps' .claude/skills/ and writes a .mcp.json registering the pracht mcp server (yes-default prompt, --no-agent-tools to skip).
  • In this repo.claude/skills symlinks to skills/, so Claude Code loads them automatically for contributors.

Repo map

Contributing

Use the GitHub issue templates for bug reports and feature requests. When opening a pull request, follow .github/PULL_REQUEST_TEMPLATE.md.

About

A framework for Preact that deploys anywhere

Resources

Stars

Watchers

Forks

Releases

Contributors

Languages