npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@rubichandrap/create-poyo-app

v0.0.3

Published

A minimal React + .NET 10 Multi-Page Application (MPA) starter framework. Features server-side routing, type-safe API integration, and zero-config HMR.

Downloads

277

Readme

Poyo

A minimal React + .NET 10 Multi-Page Application (MPA) starter framework

Poyo is an ultra-lightweight framework for building server-rendered React applications with .NET. It provides the essential scaffolding for MPA architecture without imposing opinions on authentication, database, or business logic.


🎯 The Problem Poyo Solves

ASP.NET MVC can only serve static files from wwwroot/

When building React apps with .NET MVC, you face a critical challenge:

❌ THE PROBLEM:
- ASP.NET MVC only serves static files from wwwroot/
- React source code lives in a separate client project
- You can't directly reference React components from Razor views
- You need to build React → copy to wwwroot → reference in views
- Manual process, breaks hot reload, painful developer experience

Traditional Workarounds:

  1. Separate deployments - React SPA + .NET API (loses MPA benefits)
  2. Manual copying - Build React, copy to wwwroot (tedious, error-prone)
  3. Complex build scripts - Custom tooling (hard to maintain)

✨ How Poyo Solves It

Poyo provides a complete integration between React (Vite) and .NET MVC:

✅ THE SOLUTION:
1. React source code in poyo.client/ (separate project)
2. Vite compiles React → wwwroot/generated/ (automatic)
3. Manifest generation maps hashed files → Razor partials
4. Hot reload works in development (Vite dev server)
5. Production builds automatically update references
6. Zero manual intervention required!

Development Mode:

User → .NET MVC → Razor View → Vite Dev Server (localhost:5173)
                                    ↓
                              React Hot Reload ✨

Production Mode:

npm run build
  ↓
Vite compiles React → wwwroot/generated/index-[hash].js
  ↓
generate-manifest.js creates _ReactAssets.cshtml
  ↓
.NET MVC serves from wwwroot/ with correct hashed filenames ✅

Key Features:

  • 🔥 Hot Module Replacement - React changes reload instantly in dev
  • 📦 Automatic Asset Management - Hashed filenames handled automatically
  • 🚀 Server-Side Rendering - SEO-friendly, fast initial load
  • 🎯 Type-Safe Integration - TypeScript types from OpenAPI
  • 🔐 Server Data Injection - Pass data to React without API calls
  • 🛠️ Route Management - Sync routes between server and client

✨ Features

  • 🚀 Multi-Page Architecture - Server-side routing with React hydration for SEO-friendly pages
  • 🔐 Demo Authentication - Simple cookie-based auth example (replace with your own)
  • 📦 Server Data Injection - Pass data from server to client without API calls
  • ✨ Modern Stack - React 19, TypeScript, Tailwind CSS v4, TanStack Query
  • 🎯 Type-Safe APIs - Auto-generated TypeScript types from OpenAPI
  • 🛠️ Route Management - CLI tools for managing routes between server and client

🏗️ Architecture

Poyo/
├── Poyo.Server/              # .NET 10 Server
│   ├── Controllers/          # MVC + API Controllers
│   ├── Middleware/           # Auth, Error handling
│   ├── Models/               # DTOs
│   ├── Services/             # Business logic
│   └── Views/                # Razor views
│
└── poyo.client/              # React Client
    ├── src/
    │   ├── pages/            # React pages
    │   ├── hooks/            # Custom hooks (usePage, etc.)
    │   ├── hooks-api/        # TanStack Query hooks
    │   ├── services/         # API services
    │   └── providers/        # Context providers
    └── scripts/              # Code generation tools

🚀 Quick Start

Prerequisites

  • .NET 10 SDK
  • Node.js 20+

Installation

# Create a new project
npx @rubichandrap/create-poyo-app MyApp

# Navigate to project
cd MyApp

# Install dependencies (React + .NET)
npm install
npm run restore

# Run development servers
npm run dev

Demo Credentials

  • Username: demo
  • Password: password

📚 Core Concepts

1. Server Data Injection (Server-Driven UI)

Pass data from server to client without API calls - like Laravel Livewire!

Poyo allows you to inject server-side data directly into your React components, eliminating the need for initial API calls and enabling server-driven UI patterns.

Server (C#):

[Authorize]
public IActionResult Dashboard()
{
    // Prepare data on the server
    var data = new
    {
        message = "Hello from server!",
        timestamp = DateTime.UtcNow,
        user = User.Identity?.Name,
        notifications = GetUserNotifications(),
        settings = GetUserSettings()
    };
    
    // Inject into ViewBag
    ViewBag.ServerData = JsonSerializer.Serialize(data);
    
    return View();
}

View (Razor):

@{
    ViewBag.ServerData = JsonSerializer.Serialize(new {
        message = "Data from view!",
        userId = User.FindFirst("sub")?.Value
    });
}

<div id="react-root" data-page-name="Dashboard"></div>

Client (TypeScript):

interface DashboardData {
    message: string;
    timestamp: string;
    user: string;
    notifications: Notification[];
    settings: UserSettings;
}

export default function DashboardPage() {
    // Access server data immediately - no loading state needed!
    // Validates that data is a non-null object
    const data = usePage<DashboardData>();
    
    if (!data) return <div>No data available</div>;

    return (
        <div>
            <h1>{data.message}</h1>
            <p>Server time: {data.timestamp}</p>
            <p>User: {data.user}</p>
            {/* Data is already here - no spinner, no API call! */}
        </div>
    );
}

How it works:

  1. Server renders Razor view with data in ViewBag.ServerData
  2. _Layout.cshtml injects it as window.SERVER_DATA
  3. React hydrates and usePage() reads from window.SERVER_DATA
  4. Validation: usePage() ensures data is a valid object (returns null otherwise).
  5. Zero API calls for initial page load!

Benefits:

  • Faster initial render - No loading spinners
  • SEO-friendly - Data is in HTML
  • Type-safe - TypeScript knows the shape
  • Server-driven - Like Livewire/Inertia.js
  • Secure - Data prepared server-side with auth context

Use Cases:

  • User profile data
  • Dashboard statistics
  • Notification counts
  • User preferences
  • Any data needed on page load

2. Route Management (Enhanced)

Routes are defined in routes.json and can now support Custom Controllers and Flexible SEO:

{
  "path": "/Dashboard",
  "name": "Dashboard",
  "files": {
    "react": "src/pages/Dashboard/index.page.tsx",
    "view": "Views/Dashboard/Index.cshtml"
  },
  "isPublic": false,
  "controller": "DashboardController", // Optional: Use custom controller
  "action": "Index",                   // Optional: Custom action
  "seo": {                             // Optional: SEO Metadata
    "title": "My Dashboard",
    "description": "View your stats",
    "meta": {
       "og:image": "https://..."
    },
    "jsonld": {
       "@type": "WebPage"
    }
  }
}

CLI Commands:

# Basic Add
npm run route:add YourPage

# Add with Custom Controller & Action
node scripts/manage-routes.js add /Admin --controller AdminController --action Index

# Skip View Generation (if controller handles it)
node scripts/manage-routes.js add /API/Proxy --controller ApiController --action Proxy --no-view

3. Flexible SEO System

Poyo now supports a data-driven SEO system. You don't need to touch .cshtml files for metadata.

  • Title/Description: Set in routes.json.
  • Meta Tags: Dictionary in routes.json (supports OpenGraph).
  • JSON-LD: Inject structured data scripts automatically.

All metadata is injected server-side into _Layout.cshtml before the React app even loads, ensuring perfect SEO.

3. Authentication Strategy

Poyo uses a hybrid approach to balance security and usability:

  1. Web (Browser): HttpOnly Cookies

    • Why? Protected against XSS (JavaScript can't read them). Browsers send them automatically.
    • How? Server sets an AspNetCore.Cookies cookie on login.
  2. Mobile (Native Apps): JWT (Bearer Token)

    • Why? flexible for native HTTP clients where cookies are clumsy.
    • How? Login API returns a token. Mobile apps send it in Authorization: Bearer <token>.
  3. Client UI: "UI Token"

    • What? A non-sensitive flag/token stored in localStorage.
    • Why? Instant UI updates. React knows to show "Logout" instead of "Login" immediately without waiting for a server roundtrip.
    • Security: This is NOT used for access control. The Server validates the Cookie (or Bearer token). If the cookie is missing/invalid, the request fails even if the UI token exists.
[GuestOnly]  // Redirects authenticated users
public IActionResult Login() => View();

[Authorize]  // Requires authentication
public IActionResult Dashboard() => View();

🛠️ Tech Stack

Server

  • .NET 10
  • ASP.NET Core MVC
  • Cookie Authentication

Client

  • React 19
  • TypeScript
  • Vite (Rolldown)
  • TanStack Query
  • React Hook Form + Zod
  • Tailwind CSS v4
  • Axios

📖 Project Structure

Key Files

  • routes.json - Route definitions
  • Poyo.Server/Program.cs - Server configuration
  • poyo.client/src/app.tsx - Client entry point
  • poyo.client/src/hooks/use-page.ts - Server data hook

Important Directories

  • Poyo.Server/Controllers/ - MVC controllers
  • Poyo.Server/Controllers/Api/ - API controllers
  • Poyo.Server/Middleware/Auth/ - Auth attributes
  • poyo.client/src/pages/ - React pages
  • poyo.client/scripts/ - Code generation

🎯 What's Included

Server Components

  • Cookie authentication
  • Demo auth service (replace with your own)
  • MVC routing
  • Server data injection ([ServerData] attribute)
  • Guest-only pages ([GuestOnly] attribute)
  • Error handling
  • JSend response wrapper

Client Components

  • React 19 + TypeScript
  • Form validation (React Hook Form + Zod)
  • Data fetching (TanStack Query)
  • Server data hook (usePage<T>())
  • Route management CLI
  • Tailwind CSS v4

🔧 Customization

Replace Demo Auth

The framework includes hardcoded demo auth. Replace AuthService.cs with your own implementation:

// Poyo.Server/Services/Auth/AuthService.cs
public class AuthService : IAuthService
{
    // Replace with real authentication
    // - ASP.NET Core Identity
    // - JWT tokens
    // - OAuth/OIDC
    // - Your custom solution
}

Add Database

The framework doesn't include database access. Add your own:

# Entity Framework Core
dotnet add package Microsoft.EntityFrameworkCore.SqlServer

# Or Dapper
dotnet add package Dapper

Customize Styling

Update Tailwind configuration in poyo.client/src/index.css:

@theme {
    --font-sans: YourFont, system-ui, sans-serif;
    /* Add your theme variables */
}

🤖 Code Generation

Poyo includes powerful code generation tools to keep your client and server in sync.

1. DTO Generation

Generates TypeScript types from OpenAPI specification

npm run generate:dtos
  • Fetches OpenAPI spec from server
  • Generates TypeScript types using openapi-typescript
  • Outputs to src/schemas/dtos.generated.ts
  • Requires: Server running + VITE_OPENAPI_URL in .env

2. Validation Schema Generation

Generates Zod validation schemas from TypeScript DTOs

npm run generate:schemas
  • Reads generated DTOs
  • Creates Zod schemas using ts-to-zod
  • Outputs to src/schemas/validations.generated.ts
  • Use in forms with zodResolver

3. Manifest Generation ⚠️ CRITICAL FOR PRODUCTION

Generates production asset manifest for server-side rendering

npm run generate:manifest

Why this is CRITICAL:

In development, Vite serves assets directly:

<!-- Dev mode - Vite dev server -->
<script type="module" src="http://localhost:5173/src/main.tsx"></script>

In production, Vite builds assets with hashed filenames:

dist/generated/
├── index-C2LBw7bc.css      ← Hash changes every build!
├── index-COWd0_qB.js        ← Hash changes every build!
└── vendor-SQrKxH4E.js       ← Hash changes every build!

The Problem: Your Razor views need to reference these files, but the filenames change with every build!

The Solution: generate-manifest.js reads Vite's manifest and generates _ReactAssets.cshtml:

<!-- Auto-generated - DO NOT EDIT -->
<link rel="stylesheet" href="/generated/index-C2LBw7bc.css" />
<script type="module" src="/generated/index-COWd0_qB.js"></script>
<script type="module" src="/generated/vendor-SQrKxH4E.js"></script>
<!-- Hashes updated automatically on every build! -->

How it works:

  1. npm run build compiles React app
  2. Vite creates .vite/manifest.json with file mappings
  3. generate-manifest.js reads manifest
  4. Generates _ReactAssets.cshtml with correct hashed filenames
  5. _Layout.cshtml includes this partial in production
  6. Your app loads with correct assets!

What happens if you forget:

❌ 404 errors - Assets not found
❌ Old cached assets loaded
❌ Broken production deployment
❌ White screen of death

When it runs:

  • ✅ Automatically after npm run build (via postbuild script)
  • ✅ Manually with npm run generate:manifest

Files involved:

  • Input: poyo.client/dist/.vite/manifest.json (Vite output)
  • Output: Poyo.Server/Views/Shared/_ReactAssets.cshtml (Razor partial)
  • Used by: Poyo.Server/Views/Shared/_Layout.cshtml (in production)

4. Route Management

Add new route:

npm run route:add User/Profile
# OR (with flags)
npm run route:add -- /Register --guest

What this command does:

  1. Updates routes.json: Adds entry mapping /User/Profile to the React page and Razor view.
  2. Scaffolds React Page: Creates poyo.client/src/pages/User/Profile/index.page.tsx.
    • Optionally use --flat for src/pages/User/profile.page.tsx style.
  3. Scaffolds Razor View: Creates Poyo.Server/Views/User/Profile/Index.cshtml.
    • Sets up the #root div with data-page-name="User/Profile" for hydration.

Remove route:

npm run route:remove User/Profile
  • Safe Deletion: Prompts to optionally delete both the React page and MVC View (and empty folders).

Sync routes:

npm run route:sync
  • Forward Sync: Checks for missing files and offers Rescaffold/Prune.
  • Reverse Sync: Checks for "untracked" files (React pages not in routes.json) and offers to Add/Delete them.

📝 Scripts

Client (poyo.client/)

npm run dev              # Start dev server
npm run build            # Build for production
npm run generate         # Generate DTOs + schemas
npm run generate:dtos    # Generate TypeScript types from OpenAPI
npm run generate:schemas # Generate Zod schemas from DTOs
npm run generate:dtos    # Generate TypeScript types from OpenAPI
npm run generate:schemas # Generate Zod schemas from DTOs
npm run route:add        # Add new route (supports --controller, --action, --no-view)
npm run route:sync       # Sync routes with files
npm run lint             # Run linter
npm run format           # Check formatting

Server (Poyo.Server/)

npm run dev              # Start server (dotnet run)
npm run build            # Build project (dotnet build)
npm run format           # Check C# formatting
npm run format:fix       # Fix C# formatting
npm run watch            # Watch mode (dotnet watch)
npm run publish          # Publish for production

🤝 Contributing

This is a starter framework - fork it and make it your own!


📄 License

MIT License - Use freely for any purpose


🎉 What Poyo Is NOT

  • ❌ Not a full-featured CMS
  • ❌ Not opinionated about database
  • ❌ Not opinionated about authentication
  • ❌ Not a replacement for Next.js/Remix (different architecture)

✅ What Poyo IS

  • ✅ A minimal MPA starter
  • ✅ A foundation to build upon
  • ✅ A showcase of React + .NET integration
  • ✅ A learning resource for MPA architecture

Built with ❤️ for developers who want control over their stack