bhvr

repository·main·Indexed 22 days ago

https://github.com/stevedylandev/bhvr

A full-stack TypeScript monorepo starter template designed for end-to-end type safety. Built with Bun, Hono, Vite, and React, it utilizes a shared types package to synchronize data contracts between the Hono backend server and the React client. The project uses Turbo for build orchestration across its client, server, and shared workspaces.

Tokens
2.1K
Snippets
7
Records
11
Agent score
82%

What's inside bhvr

  1. How shared types work in bhvr

    main

    The shared package is the source of truth for data contracts used by both the client and server. By defining types in shared/src/types, you achieve end-to-end type safety.

    Workflow

    1. Define a type in shared/src/types/index.ts.
    2. Export it from shared/src/index.ts using export * from "./types".
    3. Import the type in either the client or server using the shared package alias.

    When you run bun run dev or bun run build, the shared package is compiled so its exports are available to the other workspaces via TypeScript path aliases.

  2. Enable type-aware ESLint rules in the client

    main

    For production applications, it is recommended to upgrade the ESLint configuration to use type-aware lint rules. This involves replacing tseslint.configs.recommended with one of the following:

    • tseslint.configs.recommendedTypeChecked
    • tseslint.configs.strictTypeChecked (for stricter rules)
    • tseslint.configs.stylisticTypeChecked (for stylistic rules)

    You must also configure parserOptions to point to your tsconfig files.

    export default tseslint.config({
      extends: [
        // Remove ...tseslint.configs.recommended and replace with this
        ...tseslint.configs.recommendedTypeChecked,
        // Alternatively, use this for stricter rules
        ...tseslint.configs.strictTypeChecked,
        // Optionally, add this for stylistic rules
        ...tseslint.configs.stylisticTypeChecked,
      ],
      languageOptions: {
        // other options...
        parserOptions: {
          project: ['./tsconfig.node.json', './tsconfig.app.json'],
          tsconfigRootDir: import.meta.dirname,
        },
      },
    })
  3. Manage bhvr monorepo workspaces

    main

    bhvr uses Turbo for build orchestration across its workspaces (client, server, and shared). You can run commands for the entire monorepo or target specific workspaces.

    Monorepo Commands

    • Install all dependencies: bun install
    • Development (all): bun run dev
    • Build (all): bun run build
    • Lint (all): bun run lint
    • Type-check (all): bun run type-check
    • Test (all): bun run test

    Individual Workspace Commands

    • Client Dev: bun run dev:client
    • Client Build: bun run build:client
    • Server Dev: bun run dev:server
    • Server Build: bun run build:server
    # Install dependencies for all workspaces
    bun install
    
    # Run all workspaces in development mode with Turbo
    bun run dev
    
    # Or run individual workspaces directly
    bun run dev:client    # Run the Vite dev server for React
    bun run dev:server    # Run the Hono backend
  4. Create a new bhvr project

    main

    You can scaffold a new full-stack TypeScript project using the bun create command. This sets up a monorepo with a React client, a Hono server, and a shared types package.

    Ensure Bun is installed on your system before proceeding.

    bun create bhvr@latest my-app
    
    # Navigate to the project and start development
    cd my-app
    bun dev
  5. Add React-specific lint rules to ESLint

    main

    To improve code quality for React development, you can install and configure eslint-plugin-react-x and eslint-plugin-react-dom. These plugins provide specialized rules for React and React DOM components.

    // eslint.config.js
    import reactX from 'eslint-plugin-react-x'
    import reactDom from 'eslint-plugin-react-dom'
    
    export default tseslint.config({
      plugins: {
        // Add the react-x and react-dom plugins
        'react-x': reactX,
        'react-dom': reactDom,
      },
      rules: {
        // other rules...
        // Enable its recommended typescript rules
        ...reactX.configs['recommended-typescript'].rules,
        ...reactDom.configs.recommended.rules,
      },
    })
  6. Use the React client with shared types

    main

    The client workspace is a Vite + React TypeScript application. To consume the backend API with type safety, import the shared types and use the VITE_SERVER_URL environment variable to point to your Hono server.

    import { useState } from 'react'
    import { ApiResponse } from 'shared'
    
    const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000"
    
    function App() {
      const [data, setData] = useState<ApiResponse | undefined>()
    
      async function sendRequest() {
        try {
          const req = await fetch(`${SERVER_URL}/hello")
          const res: ApiResponse = await req.json()
          setData(res)
        } catch (error) {
          console.log(error)
        }
      }
    
      // ... render logic
    }
  7. Configure the Hono backend server

    main

    The server workspace uses Hono to provide a lightweight API. It is designed to be familiar to Express users. You can use Hono middleware (like cors) and return JSON data that adheres to types defined in the shared package.

    import { Hono } from 'hono'
    import { cors } from 'hono/cors'
    import type { ApiResponse } from 'shared'
    
    const app = new Hono()
    
    app.use(cors())
    
    app.get('/hello', async (c) => {
      const data: ApiResponse = {
        message: "Hello BHVR!",
        success: true
      }
    
      return c.json(data, { status: 200 })
    })
    
    export default app
  8. Use the default Hono app instance from the server package

    main

    The server package exports a default Hono application instance. This instance comes pre-configured with CORS middleware and includes the following routes:

    • GET /: Returns a plain text response 'Hello Hono!'.
    • GET /hello: Returns a JSON response containing an ApiResponse object with a success message.

    You can import this app instance to mount it on a Node.js or Bun server (e.g., using @hono/node-server or Bun.serve).

  9. Use the ApiResponse type

    main

    The ApiResponse type defines the standard structure for successful API responses within the bhvr ecosystem. It ensures that every successful response contains a descriptive message and a success flag set to true.

    export type ApiResponse = {
      message: string;
      success: true;
    }