Skip to main content

Cav

Cav is a freelancer’s web framework, made for Deno. It touts a craft-brewed development flow, combining many powerful features of TypeScript and Deno to help solo devs do more with less. Guiding principles:

  • Full stack
  • Modular, maintainable server definitions
  • Isomorphic client integration
  • Automatic end-to-end typesafety
  • Use The Platform

Status: New, active, almost fully tested, and not yet ready for production.

Goals

  • Learn as much as possible about backend web frameworks, by writing one from scratch Deno
    • Zero third-party dependencies
  • It should come with everything a solo developer would need to build a modern web app (minus the database)
    • Routing
    • Static asset serving
    • (Signed) cookies and JWTs
    • Web sockets
    • Form and JSON parsing / validation
    • De/serialization of most data types, including Files, Dates, Maps, etc.
    • Dev-time bundling for TypeScript assets
    • Works with frontend frameworks like Preact
  • “Hello world” should be as easy as deno running a tiny main.ts
    • Zero config
    • Zero CLI commands
  • The client should use types imported from the server to catch API mistakes at the IDE level automatically
    • End-to-end typesafety
    • Compatible with Zod data parsers
  • Most tasks should be typesafe without needing to write TypeScript
    • Uses inferencing and generics behind-the-scenes
    • Maximal TypeScript benefits, minimal TypeScript
  • Its syntax should be functional and declarative
    • Immutable, schema-like Router and Endpoint definitions
    • No hidden context
    • No middleware
    • No magic Yes magic 🧙‍♂️
  • Production deployments should be a simple git-commit-push

Non-goals

  • React-first
  • Built-in SSR and hydration
  • SSG
  • Strict file/folder structure
  • File-system based routing
  • Make everyone happy
  • Money

Inspirations

Notes

Links and thoughts related to Cav’s architecture.

  • HackerNews: TRPC: End-to-end typesafe APIs made easy (trpc.io)
    • Cav and tRPC scratch a similar itch, but Cav wanders a little further into Express territory.

      When I started writing what would become Cav, tRPC couldn’t (on its own) accept posted bodies that weren’t JSON, which led to a craving for an input normalization step before the parsing step that could accept both JSON and regular HTML forms. i.e. an endpoint with a single input parser could use it to parse both FormData and JSON request bodies. This would be useful in simple static sites that only need a contact or subscription form, for example.

      I was also toying around with Deno’s bundler in my spare time, and superjson was something I was using at work. I loved the thought of a comprehensive, full-stack solution that combined these ideas into a unified module, built on this standards-compliant runtime I was rapidly falling for. It seemed like writing such a framework myself would be a fun learning project.

      Lessons so far: Web frameworks are hard, Deno is awesome, and making your own tools is a great way to learn things you never knew you never knew 🍃

    • End-to-end typesafety is fairly straightforward TypeScript witchcraft. Short summary: TypeScript strips type imports at build time, making it possible to import server-side type definitions into client-side code without runtime consequences. The client can then use those types to keep API inputs/outputs in-sync with what the server expects, triggering TS errors when something isn’t right. This works without requiring code generation, which is a limitation of the venerable gRPC. Add TypeScript’s inferencing and generics to the mix, and a new world of developer tools is born.

      This is a really cool pattern to work with. A great resource to learn more is this essay written by Colin McDonnell, the creator of Zod and tRPC.

      It seems like there’s some convergent evolution going on in the community regarding this pattern, and there’s several projects mentioned in the HN comments on this post that work with similar concepts. TypeScript makes implementing this pretty simple, and Cav is just one person’s subjective take on what it can look like.

Dedication

Cav is dedicated to the bar it’s named after. 🍻