Skip to content

ChefJulio/sovereign-react

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Sovereign React

An opinionated architecture for large-scale client-side React SPAs.

Sovereign React is a set of structural decisions -- proven at scale -- for building React applications that stay fast, organized, and maintainable as they grow. Not a framework, not a library to install. It's opinions backed by working code: a starter template with a full component library, hooks, utilities, and the architectural patterns that tie them together.


Who This Is For

You're building a client-side React SPA with many independent feature pages -- a dashboard, admin panel, utility collection, educational platform, or internal tool. You don't need a server. You want it to scale to 50, 100, or 200+ pages without the bundle exploding or the codebase becoming unmaintainable.

Most React architecture guides stop at "organize your folders well." They don't address what happens when you have 100+ features: bundle size creeping up, metadata bloating the main chunk, features coupling to each other, new pages requiring changes in five places. Sovereign React solves for that.


Core Principles

  1. Client-side only. No backend for core functionality. Data stays on the user's device. Privacy by default.
  2. Feature isolation. Each page is self-contained: its own component, hook, and (optionally) core logic. No cross-feature imports.
  3. Bundle discipline. Heavy metadata stays out of the main bundle. ESLint enforces import boundaries mechanically -- not through code review.
  4. Shared infrastructure, not shared state. Reusable components, hooks, and utilities -- but no global state library. React hooks + localStorage are sufficient when features don't couple.
  5. Opinions over options. One way to do things, documented with rationale. When there's a choice, we already made it.

Quick Start

# Clone the repo
git clone https://github.com/YOUR_USERNAME/sovereign-react.git
cd sovereign-react/template

# Install and run
npm install
npm run dev

The template is a working Vite + React app with:

  • 2 example feature pages demonstrating the patterns
  • 30 shared UI components (54 at production scale)
  • 11 general-purpose hooks (18 at production scale)
  • 8 utility modules (clipboard, download, formatters, validators, etc.)
  • ESLint-enforced import boundaries
  • Dark mode, responsive layout, accessibility basics

Delete the example pages and start building your own features.


Architecture Guide

Foundation

Doc What it covers
Architecture Philosophy, stack decisions (Vite, Tailwind, React Router), and why not Next.js
Project Structure Folder conventions, file naming, what goes where
State Management localStorage strategy, React Context, why no Redux/Zustand

The Scale Story (What Makes This Different)

Doc What it covers
Routing & Registry Two-tier registry pattern, auto-generated routes, lazy metadata
Bundle Discipline ESLint import boundaries, eager vs lazy, the 89KB optimization

Building

Doc What it covers
Adding a Feature Step-by-step checklist for creating a new page
Components Shared component library API reference (30 template, 54 at scale)
Hooks Hook library API reference (11 template, 18 at scale)

Quality

Doc What it covers
Security CSP headers, DOMPurify, Web Crypto, input validation
Testing Vitest + React Testing Library patterns
Performance Debouncing, memoization, Web Workers, code splitting
Mobile 320px minimum, touch targets, responsive patterns

Advanced (Patterns at 100+ Features)

Doc What it covers
Chaining & Pipelines Feature-to-feature data flow, type system, pipeline execution
Scaling Patterns useToolSettings, useToolHistory, SEO data layer, GameShell

Why the Bundle Stays Small

Vite + React.lazy() gives you automatic per-page code splitting with zero configuration. You write this:

{ id: 'my-feature', path: '/my-feature', component: lazy(() => import('../pages/features/MyFeaturePage')) },

And Vite automatically creates a separate chunk for that page. No webpack config. No manual optimization. The page's code is only downloaded when the user navigates there. Add 200 pages and the main bundle doesn't grow -- each page is its own chunk, loaded on demand.

That's the baseline. It's free. The architecture just makes sure you don't accidentally opt out of it.

The Two-Tier Registry

The baseline handles pages, but at 50+ features a new problem appears: metadata bloat. Icons, descriptions, categories, and tags for every feature get imported into the main bundle even though they're only needed on the Home page and in search.

Sovereign React splits this into two files:

routeManifest.js -- In the main bundle. Lightweight. Just routing data.

// ~5KB -- only what the router needs
export const routeManifest = [
  { id: 'counter', path: '/counter', component: lazy(() => import('../pages/features/CounterPage')) },
  { id: 'file-processor', path: '/file-processor', component: lazy(() => import('../pages/features/FileProcessorPage')) },
  // scales to 200+ entries with minimal bundle impact
];

registry.js -- Lazy-loaded. Full metadata. Icons, descriptions, categories, tags.

// ~100KB+ -- loaded on demand by Home page, search, overlays
import { Calculator, FileText, Clock } from 'lucide-react';

export const features = [
  { id: 'counter', name: 'Counter', icon: Calculator, category: 'examples', description: '...' },
  // rich metadata for discovery, search, and display
];

ESLint enforces this boundary. If you accidentally import registry.js in an eagerly-loaded module, the linter catches it:

error: Unexpected path "./registry" imported in restricted zone.
       registry.js must not be imported in App.jsx (bloats main bundle).
       Use routeManifest.js for routing data.

This pattern reduced a production app's main bundle from 126KB to 89KB gzipped.

Read more: Routing & Registry | Bundle Discipline


Feature Structure

Every feature follows the same pattern:

src/pages/features/MyFeaturePage.jsx    # Page component (layout + UI)
src/hooks/useMyFeature.js               # Logic, state, handlers
src/components/features/MyFeature/      # Feature-specific subcomponents (if needed)

Page renders UI using shared components. Hook manages all logic and state. This separation means:

  • Logic is testable without rendering UI
  • UI is swappable without touching logic
  • Features never import from each other (ESLint-enforced)

Shared logic goes to src/hooks/, src/utils/, or src/components/shared/ -- never into another feature's folder.


Chaining & Pipelines

When features produce output that other features can consume, you can build a pipeline system on top of the architecture. This is an advanced pattern that emerged at 100+ features.

The key insight: separate processing logic from UI logic. Each chainable feature registers a pure process(input, params) function in a core registry, independent of React. A shared type system (MIME-like types: text/plain, image/png, text/json, etc.) lets the app automatically discover which features can follow which -- and suggest the next step.

The chain UI is built from composable components (ChainableOutput, ChainButton, ChainPopover) that auto-resolve feature identity from React Context. Adding chaining to a feature page is a one-line change: replace <CopyButton> with <ChainableOutput>.

Read more: Chaining & Pipelines


Shared Component Library

The template includes 30 production-ready components:

Form Controls: Button, Input, Textarea, Select, Toggle, Slider, RadioGroup Display: Card, Alert, EmptyState, LoadingSpinner, KeyValueList, ResultDisplay Actions: CopyButton, DownloadButton, FileUpload Navigation: TabGroup, ModeToggle, PresetButtons Overlays: ConfirmDialog, InfoDialog, Toast (context-based) Layout: SplitPane, FeatureLayout, ToolSection, HistoryPanel Batch Processing: BatchInput, BatchPreviewGrid, FileProcessorLayout

All components use Tailwind CSS with dark mode support. See Components Reference for full API documentation.

In production (Overtooled, 178+ features), the library grew to 54 components. Key additions: chain system UI (ChainableOutput, ChainButton, ChainPopover, ChainStepCard, ChainParamForm, ChainSuggestionList), game support (GameShell), data display (StatCard, Table, CodeBlock), and navigation (CommandPalette, SearchDropdown, RelatedTools).


Hook Library

11 general-purpose hooks included:

Hook Purpose
useLocalStorage Persistent state with cross-instance sync via custom events
useDebounce Debounce any value with configurable delay
useClipboard Copy to clipboard with fallback and status tracking
useAsync Async operations with loading/error state and stale-result prevention
useFileUpload File reading with type/size validation
useKeyboardShortcut Keyboard shortcuts with modifier support
useInterval setInterval with React lifecycle management
useUndo Undo/redo state history
useMediaQuery Responsive breakpoint detection
useFullscreen CSS-based fullscreen overlay
useObjectURL Blob URL management with automatic cleanup

See Hooks Reference for full API documentation.

In production, 7 more general-purpose hooks emerged: useToolSettings (per-feature settings), useToolHistory (per-feature history), useFavorites, useRecentTools, useStopwatch, useTimer, and useVersionCheck. The chain system added 4 specialized hooks: useChainExecution, useMultiChainTabs, useUsageGraph, and useSavedPipelines. See Scaling Patterns.


Stack

Layer Choice Why
Build Vite Fast dev server, optimized production builds, minimal config
UI React 18 Component model, hooks, lazy loading
Styling Tailwind CSS Utility-first, dark mode, responsive, zero CSS file management
Routing React Router v6 Standard SPA routing, lazy-loaded routes
State React hooks + localStorage No global state needed when features are isolated
Testing Vitest + React Testing Library Fast, React-native, behavior-focused
Linting ESLint + eslint-plugin-import-x Import boundary enforcement

Proven at Scale

This architecture powers Overtooled, a collection of 178+ client-side web utilities. At that scale:

  • Main bundle: 89KB gzipped (with 178 lazy-loaded routes)
  • Each feature adds ~10-20KB on demand
  • No cross-feature coupling
  • Adding a new feature is a 3-file operation (page + hook + registry entries)
  • Feature-to-feature chaining via a type-safe pipeline system
  • 54 shared components, 18 general-purpose hooks, 6 React Contexts
  • Zero backend, zero server costs, instant tool responses

The patterns here aren't theoretical -- they've been battle-tested at production scale.


Contributing

This is an opinionated guide, not a community-driven framework. That said:

  • Bug reports and corrections are welcome
  • If you've used these patterns at scale, share your experience in Discussions
  • PRs for new docs or improved explanations are appreciated

License

MIT

About

An opinionated architecture for large-scale client-side React SPAs

Resources

License

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages