The final product is williannguyen.com.
Full personal reflection on this project can be found on this post.
Note:
There is a regular status service to check that the website should work. This is one of the feature can be seen in the source code. If it does not (mismatch with status), please dm me. Thank you for your helps.
This application follows a full-stack Rust architecture using:
- Frontend: Leptos with hydration for interactive client-side features
- Backend: Axum web framework
- Rendering: Server-side rendering (SSR) with client-side hydration
- Content: Markdown-based blog posts with syntax highlighting
- Build System: Custom build script for static content generation
- Planned Database: SurrealDB
- Leptos 0.8 - Reactive web framework for Rust
- Axum 0.8 - Modern async web framework
- Tokio - Async runtime
- SurrealDB - Multi-model database (planned for newsletter subscriber feature)
- pulldown-cmark - Markdown parser
- syntect - Syntax highlighting for code blocks
- Static Content Generation - Build-time markdown processing
- cargo-leptos - Leptos build tool
- Hot Reload - Development server with live reloading
- WASM Optimization - Size-optimized WebAssembly builds
- End-to-End Testing - Playwright integration
Built with Leptos 0.8 using SSR + hydration pattern. The frontend follows a responsive component architecture with clear separation of desktop/mobile layouts.
src/
βββ client.rs # Client-side hydration entry point
βββ lib.rs # Shared library code
βββ app/
β βββ mod.rs # Root App component with header/footer
β βββ helpers.rs # UI utility functions
β βββ components/ # Reusable UI components
β β βββ nav/ # Navigation (responsive desktop/mobile)
β β β βββ mod.rs # Nav coordinator
β β β βββ desktop.rs # Desktop navigation (>768px)
β β β βββ mobile.rs # Mobile navigation (β€768px)
β β β βββ helpers.rs # Shared nav logic & parameterized components
β β βββ footer/ # Footer (responsive desktop/mobile)
β β β βββ mod.rs # Footer coordinator
β β β βββ desktop.rs # Desktop footer layout
β β β βββ mobile.rs # Mobile footer layout
β β β βββ helpers.rs # Copyright & NewsletterSection components
β β β βββ subscribe_form.rs # AutoForm-based newsletter form
β β βββ post_nav/ # Post navigation (prev/next links)
β β β βββ mod.rs # PostNav coordinator
β β β βββ desktop.rs # Horizontal layout
β β β βββ mobile.rs # Vertical stacked layout
β β β βββ helpers.rs # BackToTop & PostLink components
β β βββ ui/ # rust-ui components (theme toggle, etc.)
β β βββ fast_a.rs # Enhanced anchor component
β β βββ content_list.rs # Dynamic post/poem list rendering
β β βββ icons.rs # Icon mapping utilities
β β βββ theme_toggle.rs # Dark/light mode switcher
β βββ pages/ # Route-level page components
β β βββ mod.rs # Page coordinator
β β βββ homepage.rs # Landing page
β β βββ postpage.rs # Blog post list & detail pages
β β βββ poempage.rs # Poetry list & detail pages
β βββ hooks/ # Custom reactive hooks
β βββ use_theme_mode.rs # Theme state management with localStorage
βββ server/ # Backend (see Backend section)
βββ shared/ # Shared DTOs between frontend/backend
βββ dto.rs
- Responsive Module Pattern: Each complex component (
nav/,footer/,post_nav/) uses a directory structure withmod.rs(coordinator),desktop.rs,mobile.rs, andhelpers.rs(shared logic) - Parameterized Components: Shared UI elements (e.g.,
SocialLinks,NavLinks) accept class prefixes for layout variants without duplication - Theme Management: Reactive theme state persisted to localStorage, with SSR-compatible hydration
- Static Content: Markdown posts/poems processed at build time, rendered as static HTML with syntax highlighting
- rust-ui Integration: Uses rust-ui ecosystem for form generation (
autoform), icons (iconscrate with Leptos feature), and UI primitives - CSS Strategy: PicoCSS base + Tailwind CSS v4 + custom semantic stylesheets in
public/style/
The backend structure seen below is over-engineered for the purpose of personal blog with only public newsletter subcriber feature.
However, the industry-graded architecture is purposely used to study fullstack technology with Rust. The architecture is learnt from the book FullStack Rust with Axum from Martin Fabio
βββ main.rs # Application entry point
βββ server.rs # Server orchestration & middleware stack
βββ server/ # Modular backend architecture
βββ db.rs # Database module coordinator
βββ db/
β βββ config.rs # Database URL & connection config
β βββ pool.rs # PgPool initialization & management
β βββ state.rs # AppState with shared resources
β βββ error.rs # Database-specific error handling
βββ middleware.rs # Middleware module coordinator
βββ middleware/
β βββ cache.rs # HTTP caching strategies
β βββ governor.rs # Rate limiting (IP-based)
β βββ csrf.rs # CSRF token protection
β βββ throttle.rs # Request throttling
β βββ global_layer.rs # Middleware layer coordinator
β βββ global_layer/
β βββ cors.rs # Cross-Origin Resource Sharing
β βββ security_headers.rs # Security headers middleware
βββ models.rs # Data model coordinator
βββ models/
β βββ subscriber.rs # Newsletter subscriber model
β βββ status.rs # Status badge model (for shields.io)
βββ repositories.rs # Data access coordinator
βββ repositories/
β βββ subscriber.rs # Database queries & data access
β βββ status.rs # Status badge logic (checks and aggregates status)
βββ services.rs # Business logic coordinator
βββ services/
β βββ subscriber.rs # Newsletter business logic
β βββ status.rs # Status badge update logic (periodic background updater)
βββ handlers.rs # Request handler coordinator
βββ handlers/
β βββ subscriber.rs # HTTP request/response handling
β βββ status.rs # Status badge API handler (serves cached status)
βββ routes.rs # API route coordinator
βββ routes/
βββ subscriber.rs # Newsletter API endpoints
βββ status.rs # Status badge AP endpoint (`/status-badge` for shields.io)
graph TD
Middleware["π§© Middleware Stack<br/>(server.rs & routes/)"]
Middleware -->|Applied globally and per route| Routes["π£οΈ Routes"]
Routes -->|Use| Handlers["π Handlers"]
Handlers -->|Use| Services["ποΈ Services"]
Services -->|Use| Repositories["π¦ Repositories"]
Repositories -->|Use| Models["π Models"]
Repositories -->|Use| DB["ποΈ DB"]
- Global
- Compression: Brotli compression for responses
- Request Timeout: Configurable request timeouts
- Security Headers: Comprehensive HTTP security headers
- Route specific
- Rate Limiting: Per-IP request throttling using Governor
- CORS: Cross-Origin Resource Sharing configuration
- CSRF Protection: Token-based CSRF mitigation
- Routes: HTTP endpoints + middleware application, delegate to handlers
- Handlers: HTTP request/response processing, input validation
- Services: Business logic, orchestration, transaction management
- Repositories: Data access queries, DB operations using models
- Models: Data structures, serialization, validation rules
- DB: Connection pooling, configuration, state management
The project uses a custom build script (build.rs) that:
- Processes Markdown Files: Reads blog posts from
contents/posts/ - Syntax Highlighting: Applies code highlighting using Syntect
- Static Generation: Converts markdown to HTML at build time
- Optimized Output: Generates Rust code with static post data
- Server-Side Rendering (SSR): Fast initial page loads
- Hydration: Interactive client-side features without full SPA overhead
- Static Content: Build-time markdown processing reduces runtime overhead
- Compression: Brotli compression for smaller payload sizes
- Connection Pooling: Efficient database connection management
- Request Timeout: Prevents long-running requests from blocking resources
- HTTP Caching Strategy: Multi-tier caching system for optimal performance
- WASM Optimization: Aggressive size optimization for client-side bundles
The WebAssembly build process includes several standard optimization techniques to minimize bundle size:
- Size-focused compilation (opt-level = 'z')
- Link-time optimization (LTO)
- Strip debug symbols (strip = true)
- Abort on panic (panic = "abort")
- Single codegen unit
- Use wee_alloc for smaller WASM allocator
Below information is obtained from the actual implementation on the project and get benchmark to show the efficency of these technuques.
| Metric | Before Optimization | After Optimization | Improvement |
|---|---|---|---|
| Bundle Size | 8.5MB | 1.5MB | 82.4% smaller |
| Gzipped Size | ~2.1MB | ~400-600KB | ~75% smaller |
| Load Time Impact | Baseline | Significantly improved | 5.6x smaller |
- Faster page loads: 82% smaller WASM bundles load much faster
- Reduced bandwidth: Significant savings in data transfer
- Better mobile experience: Smaller bundles improve performance on slower connections
- Production ready: Size is now within reasonable limits for web deployment
Deploy standard industry practices
- Static Assets:
- Uses
Cache-Control: public, max-age=31536000for 1-year caching. - Assets are versioned for cache busting, ensuring users get updates when files change.
- Uses
- API Responses:
- Uses
Cache-Control: public, max-age=60for short-term caching (1 minute). - Improves performance for read-only endpoints and reduces database load.
- Uses
- Sensitive/Dynamic Endpoints:
- Uses
Cache-Control: no-storeto prevent caching of user actions and sensitive data.
- Uses
- Centralized Error Handling (Status: Planned)
To add a middleware layer to catch errors, log them, and provide consistent user-friendly responses. Implementation is postponed until the app grows in complexity.
- Modulized global layer (Status: Planned)
This was planned out at the begginning with tower crate 's ServiceBuilder as a global layer which is then called into server.rs. However, refactoring this seperated out from server.rs run is more troublesome than expected. Until the project expands further, it is placed directly in server.rs.
- Book FullStack Rust with Axum from Martin Fabio
- Leptos resources
- awesome-leptos repo
- The wild internet, AIs and various other sources...