reinhardt-pages
WASM-based reactive frontend framework for Reinhardt with Django-like API.
Features
- Fine-grained Reactivity: Leptos/Solid.js-style Signal system with automatic dependency tracking
- Hybrid Rendering: SSR + Client-side Hydration for optimal performance and SEO
- Django-like API: Familiar patterns for Reinhardt developers
- Low-level Only: Built on wasm-bindgen, web-sys, and js-sys (no high-level framework dependencies)
- Security First: Built-in CSRF protection, XSS prevention, and session management
- Simplified Conditional Compilation:
cfg_aliasesintegration and automatic event handler handling
Quick Start
Using the Prelude (Recommended)
The prelude provides all commonly used types with a single import:
// Instead of multiple scattered imports:
// use reinhardt_pages::{Signal, View, use_state, ...};
// use reinhardt_pages::component::{ElementView, IntoView};
// use reinhardt_pages::reactive::{Effect, Memo};
// Use the unified prelude:
use *;
// or via reinhardt crate:
use *;
Platform-Agnostic Event Type
The platform module provides unified types that work across both WASM and native:
use Event;
// Works on both WASM and native targets
Simplified cfg Attributes with cfg_aliases
Configure cfg_aliases in your project's build.rs:
// build.rs
use cfg_aliases;
Add to Cargo.toml:
[]
= "0.2"
Now you can use shorter cfg attributes:
// Before:
// After:
// Before:
// After:
Automatic Event Handler Handling
The page! macro automatically handles event handlers for server-side rendering. You no longer need to write duplicate conditional blocks:
use *;
// This works on both WASM and native targets!
// On WASM: Event handlers are bound to DOM events
// On native: Event handlers are automatically ignored
Before (manual conditional compilation):
After (automatic handling):
// Just write once - the macro handles everything!
page!
Reactive Conditional Rendering with watch
The watch { expr } syntax enables reactive re-rendering when Signal dependencies change. Unlike static if conditions that are evaluated only at render time, watch blocks automatically re-evaluate and update the DOM when their Signal dependencies change.
Why watch is Needed
When you extract Signal values before the page! macro, they become static:
// Problem: Static values don't update when Signal changes
let has_error = error.get.is_some; // Static bool captured at render time
page!
The watch syntax solves this by creating a reactive context:
// Solution: Pass Signal directly and use watch
page!
Signal-first Pattern
For reactive UIs, pass Signals directly to the page! macro instead of extracting values:
use *;
watch vs Static if
| Syntax | Use Case | Behavior |
|---|---|---|
if condition { ... } |
Static conditions, Copy types | Evaluated once at render time |
watch { if signal.get() { ... } } |
Signal-dependent conditions | Re-evaluates when Signal changes |
watch { match signal.get() { ... } } |
Multiple reactive branches | Re-evaluates when Signal changes |
Using watch with match
The watch block also supports match expressions:
page!
Best Practices
- Pass Signals directly: Use
Signal<T>parameters instead of extracting values - Clone Signals:
Signal::clone()is cheap (Rc-based), so clone freely - Single expression:
watchblocks must contain exactly one expression - Avoid nesting: Don't nest
watchblocks (performance concern)
Architecture
This framework consists of several key modules:
reactive: Fine-grained reactivity system (Signal, Effect, Memo)dom: DOM abstraction layerbuilder: HTML element builder APIcomponent: Component system with IntoView traitform: Django Form integration (native only)csrf: CSRF protectionauth: Authentication integrationapi: API client with Django QuerySet-like interfaceserver_fn: Server Functions (RPC)ssr: Server-side renderinghydration: Client-side hydrationrouter: Client-side routing (reinhardt-urls compatible)platform: Platform abstraction typesprelude: Unified imports
Prelude Contents
The prelude includes:
Reactive System
Signal,Effect,Memo,Resource,ResourceState- Context:
Context,ContextGuard,create_context,get_context,provide_context,remove_context
Hooks
use_state,use_effect,use_memo,use_callback,use_contextuse_ref,use_reducer,use_transition,use_deferred_valueuse_id,use_layout_effect,use_effect_event,use_debug_valueuse_optimistic,use_action_state,use_shared_state,use_sync_external_store
Component System
Component,ElementView,IntoView,View,Props,ViewEventHandler
Events and Callbacks
Callback,IntoEventHandler,into_event_handlerEvent(platform-agnostic viaplatformmodule)
DOM
Document,Element,EventHandle,EventType,document
Routing
Link,Router,Route,RouterOutlet,PathPattern
API and Server Functions
ApiModel,ApiQuerySet,Filter,FilterOpServerFn,ServerFnError- See Server Function Macro Guide for detailed usage and migration information
Authentication and Security
AuthData,AuthError,AuthState,auth_stateCsrfManager,get_csrf_token
SSR and Hydration
HydrationContext,HydrationError,hydrateSsrOptions,SsrRenderer,SsrState
Forms (native only)
FormBinding,FormComponentWidget,FieldMetadata,FormMetadata
Macros
page!
WASM-specific
spawn_local(re-exported from wasm_bindgen_futures)create_resource,create_resource_with_deps
Example
use *;
Feature Flags
| Feature | Description |
|---|---|
msgpack |
MessagePack serialization support |
pages-full |
All features enabled |
static |
Static file serving |
urls |
URL routing integration |
License
Licensed under the BSD 3-Clause License.