Skip to content

wscld/react-server-app

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

26 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

react-server-app

A React-based server framework where you define routes using JSX components, combining the power of React with Fastify's performance.

TypeScript React Fastify Bun npm version License: MIT

✨ Features

  • 🎯 JSX as Configuration - Define routes declaratively with React components
  • πŸ›‘οΈ Guards & Middleware - Built-in support for authentication and request processing
  • πŸ”’ TypeScript-First - Full type safety with generic type parameters
  • ⚑ Fastify Powered - Blazing fast HTTP server under the hood
  • 🎨 Nested Routes - Organize routes with <Controller> components
  • πŸ“„ Page Rendering - SSR and SPA support with automatic bundling
  • βš›οΈ Full React SPA - Build interactive pages with hooks, state, and effects
  • πŸ”„ Hot Reload - Development mode with automatic cache invalidation
  • 🎭 "use spa" Directive - Auto-discovery of SPA components at startup
  • πŸš€ Bun & Node Compatible - Works with both runtimes seamlessly

πŸ“¦ Installation

# Using Bun (recommended)
bun add react-server-app react react-dom

# Using npm
npm install react-server-app react react-dom

# For SPA mode, also install:
bun add vite @vitejs/plugin-react
# or
npm install vite @vitejs/plugin-react

πŸš€ Quick Start

import React from "react";
import { App, Route, createServer } from "react-server-app";

const server = (
  <App port={3000}>
    <Route path="/hello" method="GET" onRequest={() => ({ message: "Hello World!" })} />
  </App>
);

createServer(server);

Run with:

bun run server.tsx
# or
tsx server.tsx

Visit http://localhost:3000/hello

πŸ“š See Full Quick Start Guide

πŸ“– Documentation

πŸ’‘ Examples

Simple API Route

<Route
  path="/users/:id"
  method="GET"
  onRequest={({ params }) => ({
    userId: params.id,
    name: "John Doe",
  })}
/>

Nested Controllers

<Controller path="/api">
  <Controller path="/users">
    <Route path="/" method="GET" onRequest={() => getAllUsers()} />
    <Route path="/:id" method="GET" onRequest={({ params }) => getUser(params.id)} />
    <Route path="/" method="POST" onRequest={({ body }) => createUser(body)} />
  </Controller>
</Controller>

Protected Routes with Guards

<Guard use={authGuard}>
  <Route path="/dashboard" method="GET" onRequest={getDashboard} />
  <Route path="/profile" method="GET" onRequest={getProfile} />
</Guard>

SPA Page with React Hooks

// dashboard.tsx
"use spa";

import { useState } from "react";

export default function Dashboard() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <h1>Count: {count}</h1>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

// server.tsx
<Route
  path="/dashboard"
  method="GET"
  onRequest={() => (
    <Page spa={true} title="Dashboard">
      <Dashboard />
    </Page>
  )}
/>;

🎯 Core Concepts

Components

  • <App> - Root component that starts the server
  • <Controller> - Groups routes under a common path
  • <Route> - Defines HTTP endpoints
  • <Guard> - Protects routes with authorization logic
  • <Middleware> - Processes requests before handlers
  • <Page> - Renders HTML pages (SSR or SPA)
  • <Response> - Declarative response formatting

TypeScript Support

Full type safety with generic type parameters:

interface UserParams {
  id: string;
}

interface User {
  id: string;
  name: string;
  email: string;
}

<Route<UserParams, never, never, User>
  path="/users/:id"
  method="GET"
  onRequest={({ params }) => {
    // params.id is typed as string
    return {
      id: params.id,
      name: "John Doe",
      email: "john@example.com",
    };
  }}
/>;

πŸ”§ Configuration

Configure the framework to your needs:

import { configure } from "react-server-app";

configure({
  bundler: "vite", // or 'bun'
  minify: true, // Minify bundles
  cache: true, // Enable caching
  spaComponentDirs: [
    // Directories to scan for "use spa"
    "pages",
    "components",
  ],
  spaComponentExclude: [
    // Directories to exclude
    "node_modules",
    "dist",
  ],
});

πŸ“– Full Configuration Guide

πŸš€ Advanced Features

Hot Reload

Development mode automatically watches your files and clears the cache when changes are detected. No server restart needed!

// Just save your file and changes are reflected immediately

"use spa" Directive

Auto-discover SPA components at startup:

// pages/Dashboard.tsx
"use spa";

export default function Dashboard() {
  return <div>Auto-discovered!</div>;
}

No registration needed - the framework finds it automatically.

πŸ“– Read the full guide

Modular Bundler System

Supports multiple bundlers with a clean plugin architecture:

  • Bun Bundler - Native Bun bundling (very fast)
  • Vite Bundler - Industry-standard bundler (Node.js compatible)

Add your own bundler by implementing the Bundler interface!

πŸ“š Complete Example

Check out the demo application for a complete working example with:

  • Authentication guards
  • CORS middleware
  • API routes
  • Interactive SPA pages
  • TypeScript types
  • "use spa" directive usage

🀝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

πŸ“ License

MIT

πŸ‘€ Author

Wesley Caldas

πŸ”— Links


Built with ❀️ using React, Fastify, and TypeScript