|
1 | 1 | # Willian's Personal Blog |
2 | 2 |
|
3 | | -Visit: [williannguyen.com](https://www.williannguyen.com) |
| 3 | +The blog is at [wiiliannguyen.com](https://www.williannguyen.com) |
4 | 4 |
|
5 | | -## Overview |
| 5 | +## Architecture Overview |
6 | 6 |
|
7 | | -A fast, modern blog built with full-stack Rust: |
| 7 | +This application follows a **full-stack Rust architecture** using: |
8 | 8 |
|
9 | | -- **Frontend:** Leptos (SSR + hydration) |
10 | | -- **Backend:** Axum + PostgreSQL |
11 | | -- **Content:** Markdown posts, syntax highlighting |
12 | | -- **Build:** Static content generation at compile time |
| 9 | +- **Frontend**: Leptos with hydration for interactive client-side features |
| 10 | +- **Backend**: Axum web framework with PostgreSQL database |
| 11 | +- **Rendering**: Server-side rendering (SSR) with client-side hydration |
| 12 | +- **Content**: Markdown-based blog posts with syntax highlighting |
| 13 | +- **Build System**: Custom build script for static content generation |
13 | 14 |
|
14 | | -## Features |
| 15 | +## Tech Stack |
15 | 16 |
|
16 | | -- Server-side rendering for speed |
17 | | -- WASM-optimized client bundle |
18 | | -- Markdown-based posts |
19 | | -- Syntax highlighting for code |
20 | | -- Multi-tier caching for assets and APIs |
21 | | -- Security: rate limiting, CORS, CSRF, security headers, cache |
22 | | -- Newsletter subscription |
| 17 | +### Core Framework |
23 | 18 |
|
24 | | -## Structure |
| 19 | +- **[Leptos 0.8](https://leptos.dev/)** - Reactive web framework for Rust |
| 20 | +- **[Axum 0.8](https://docs.rs/axum/)** - Modern async web framework |
| 21 | +- **[Tokio](https://tokio.rs/)** - Async runtime |
| 22 | + |
| 23 | +### Database & ORM |
| 24 | + |
| 25 | +- **[PostgreSQL](https://www.postgresql.org/)** - Primary database |
| 26 | +- **[SQLx 0.8](https://docs.rs/sqlx/)** - Async SQL toolkit with compile-time checked queries |
| 27 | +- **Database Migrations** - Version-controlled schema management |
| 28 | + |
| 29 | +### Content Processing |
| 30 | + |
| 31 | +- **[pulldown-cmark](https://docs.rs/pulldown-cmark/)** - Markdown parser |
| 32 | +- **[syntect](https://docs.rs/syntect/)** - Syntax highlighting for code blocks |
| 33 | +- **Static Content Generation** - Build-time markdown processing |
| 34 | + |
| 35 | +### Middleware & Security |
| 36 | + |
| 37 | +- **Rate Limiting** - Per-IP request throttling using Governor |
| 38 | +- **CORS** - Cross-Origin Resource Sharing configuration |
| 39 | +- **CSRF Protection** - Token-based CSRF mitigation |
| 40 | +- **Security Headers** - Comprehensive HTTP security headers |
| 41 | +- **Request Timeout** - Configurable request timeouts |
| 42 | +- **Compression** - Brotli compression for responses |
| 43 | + |
| 44 | +### Development & Deployment |
| 45 | + |
| 46 | +- **[cargo-leptos](https://crates.io/crates/cargo-leptos)** - Leptos build tool |
| 47 | +- **Hot Reload** - Development server with live reloading |
| 48 | +- **WASM Optimization** - Size-optimized WebAssembly builds |
| 49 | +- **End-to-End Testing** - Playwright integration |
| 50 | + |
| 51 | +## Project Structure |
| 52 | + |
| 53 | +### 🌐 Frontend (Leptos) |
| 54 | + |
| 55 | +The implementation is obtained from cargo-leptos axum template provided from. For more detail, please follow the the [instruction](https://github.com/leptos-rs/start-axum). |
25 | 56 |
|
26 | 57 | ```text |
27 | 58 | src/ |
28 | | - app.rs # Main app & routing |
29 | | - app/ |
30 | | - components/ # UI components (nav, footer, theme toggle, etc.) |
31 | | - pages/ # Route-level pages (home, post, poem) |
32 | | - helpers.rs # Shared utilities |
33 | | - server.rs # Axum server setup |
34 | | - server/ # Backend modules (db, middleware, models, routes, handlers,services, repositories,...) |
35 | | - build.rs # Static content build script |
36 | | - contents/ # Markdown posts |
| 59 | +├── app.rs # App component and routing |
| 60 | +├── client.rs # Client-side hydration entry |
| 61 | +├── app/ |
| 62 | +│ ├── helpers.rs # UI utility functions |
| 63 | +│ ├── components.rs # Component module definitions |
| 64 | +│ ├── components/ |
| 65 | +│ ├── pages.rs |
| 66 | +│ └── pages/ # Page module definitions |
37 | 67 | ``` |
38 | 68 |
|
39 | | -## Build & Deploy |
| 69 | +### ⚙️ Backend (Axum) Architecture |
| 70 | + |
| 71 | +The backend structure seen below is over-engineered for the purpose of personal blog with only public newsletter subcriber feature. |
| 72 | + |
| 73 | +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](https://www.amazon.com/FullStack-Rust-Axum-Server-Rendered-High-Performance-ebook/dp/B0FM6XF8YX) |
| 74 | + |
| 75 | +```text |
| 76 | +├── main.rs # Application entry point |
| 77 | +├── server.rs # Server orchestration & middleware stack |
| 78 | +└── server/ # Modular backend architecture |
| 79 | + ├── db.rs # Database module coordinator |
| 80 | + ├── db/ |
| 81 | + │ ├── config.rs # Database URL & connection config |
| 82 | + │ ├── pool.rs # PgPool initialization & management |
| 83 | + │ ├── state.rs # AppState with shared resources |
| 84 | + │ └── error.rs # Database-specific error handling |
| 85 | + ├── middleware.rs # Middleware module coordinator |
| 86 | + ├── middleware/ |
| 87 | + │ ├── cache.rs # HTTP caching strategies |
| 88 | + │ ├── governor.rs # Rate limiting (IP-based) |
| 89 | + │ ├── csrf.rs # CSRF token protection |
| 90 | + │ ├── throttle.rs # Request throttling |
| 91 | + │ ├── global_layer.rs # Middleware layer coordinator |
| 92 | + │ └── global_layer/ |
| 93 | + │ ├── cors.rs # Cross-Origin Resource Sharing |
| 94 | + │ └── security_headers.rs # Security headers middleware |
| 95 | + ├── models.rs # Data model coordinator |
| 96 | + ├── models/ |
| 97 | + │ └── subscriber.rs # Newsletter subscriber model |
| 98 | + ├── repositories.rs # Data access coordinator |
| 99 | + ├── repositories/ |
| 100 | + │ └── subscriber.rs # Database queries & data access |
| 101 | + ├── services.rs # Business logic coordinator |
| 102 | + ├── services/ |
| 103 | + │ └── subscriber.rs # Newsletter business logic |
| 104 | + ├── handlers.rs # Request handler coordinator |
| 105 | + ├── handlers/ |
| 106 | + │ └── subscriber.rs # HTTP request/response handling |
| 107 | + ├── routes.rs # API route coordinator |
| 108 | + └── routes/ |
| 109 | + └── subscriber.rs # Newsletter API endpoints |
| 110 | +``` |
| 111 | + |
| 112 | +### 🏘️ Backend Layer Relationships |
| 113 | + |
| 114 | +<div style="display: flex; gap: 2em;"> |
| 115 | + <div style="flex: 1; min-width: 300px;"> |
| 116 | + |
| 117 | +```mermaid |
| 118 | +graph TD |
| 119 | + Middleware["🧩 Middleware Stack<br/>(server.rs & routes/)"] |
| 120 | + Middleware -->|Applied globally and per route| Routes["🛣️ Routes"] |
| 121 | + Routes -->|Use| Handlers["👐 Handlers"] |
| 122 | + Handlers -->|Use| Services["🛎️ Services"] |
| 123 | + Services -->|Use| Repositories["📦 Repositories"] |
| 124 | + Repositories -->|Use| Models["📄 Models"] |
| 125 | + Repositories -->|Use| DB["🗄️ DB"] |
| 126 | +``` |
| 127 | + |
| 128 | +</div> |
| 129 | + <div style="flex: 1; min-width: 300px;"> |
| 130 | + <b>Middleware & Security Features</b> |
| 131 | + <ul> |
| 132 | + <li>Rate Limiting: Per-IP request throttling using Governor</li> |
| 133 | + <li>CORS: Cross-Origin Resource Sharing configuration</li> |
| 134 | + <li>CSRF Protection: Token-based CSRF mitigation</li> |
| 135 | + <li>Security Headers: Comprehensive HTTP security headers</li> |
| 136 | + <li>Request Timeout: Configurable request timeouts</li> |
| 137 | + <li>Compression: Brotli compression for responses</li> |
| 138 | + </ul> |
| 139 | + <b>Middleware Implementation</b> |
| 140 | + <ul> |
| 141 | + <li>Global: Applied in server.rs (compression, timeout, CORS, security headers)</li> |
| 142 | + <li>Route-specific: Applied in routes/ modules. For example, subscriber routes apply no_cache, governor, throttle, and CSRF layers.</li> |
| 143 | + </ul> |
| 144 | + <b>Layer Responsibilities</b> |
| 145 | + <ul> |
| 146 | + <li>Routes: HTTP endpoints + middleware application, delegate to handlers</li> |
| 147 | + <li>Handlers: HTTP request/response processing, input validation</li> |
| 148 | + <li>Services: Business logic, orchestration, transaction management</li> |
| 149 | + <li>Repositories: Data access queries, DB operations using models</li> |
| 150 | + <li>Models: Data structures, serialization, validation rules</li> |
| 151 | + <li>DB: Connection pooling, configuration, state management</li> |
| 152 | + </ul> |
| 153 | + </div> |
| 154 | +</div> |
| 155 | + |
| 156 | +## Build System |
| 157 | + |
| 158 | +The project uses a custom build script (`build.rs`) that: |
40 | 159 |
|
41 | | -- Build with `cargo-leptos` |
42 | | -- Deploy to Fly.io with managed Postgres |
| 160 | +1. **Processes Markdown Files**: Reads blog posts from `contents/posts/` |
| 161 | +2. **Syntax Highlighting**: Applies code highlighting using Syntect |
| 162 | +3. **Static Generation**: Converts markdown to HTML at build time |
| 163 | +4. **Optimized Output**: Generates Rust code with static post data |
| 164 | + |
| 165 | +## Performance Features |
| 166 | + |
| 167 | +- **Server-Side Rendering (SSR)**: Fast initial page loads |
| 168 | +- **Hydration**: Interactive client-side features without full SPA overhead |
| 169 | +- **Static Content**: Build-time markdown processing reduces runtime overhead |
| 170 | +- **Compression**: Brotli compression for smaller payload sizes |
| 171 | +- **Connection Pooling**: Efficient database connection management |
| 172 | +- **Request Timeout**: Prevents long-running requests from blocking resources |
| 173 | +- **HTTP Caching Strategy**: Multi-tier caching system for optimal performance |
| 174 | +- **WASM Optimization**: Aggressive size optimization for client-side bundles |
| 175 | + |
| 176 | +## WASM Bundle Optimization |
| 177 | + |
| 178 | +The WebAssembly build process includes several standard optimization techniques to minimize bundle size: |
| 179 | + |
| 180 | +### Optimization Techniques |
| 181 | + |
| 182 | +- Size-focused compilation (opt-level = 'z') |
| 183 | +- Link-time optimization (LTO) |
| 184 | +- Strip debug symbols (strip = true) |
| 185 | +- Abort on panic (panic = "abort") |
| 186 | +- Single codegen unit |
| 187 | +- Use wee_alloc for smaller WASM allocator |
| 188 | + |
| 189 | +### Benchmark Results |
| 190 | + |
| 191 | +Below information is obtained from the actual implementation on the project and get benchmark to show the efficency of these technuques. |
| 192 | + |
| 193 | +| Metric | Before Optimization | After Optimization | Improvement | |
| 194 | +|--------|--------------------|--------------------|-------------| |
| 195 | +| **Bundle Size** | 8.5MB | 1.5MB | **82.4% smaller** | |
| 196 | +| **Gzipped Size** | ~2.1MB | ~400-600KB | ~75% smaller | |
| 197 | +| **Load Time Impact** | Baseline | Significantly improved | 5.6x smaller | |
| 198 | + |
| 199 | +### Impact |
| 200 | + |
| 201 | +- **Faster page loads**: 82% smaller WASM bundles load much faster |
| 202 | +- **Reduced bandwidth**: Significant savings in data transfer |
| 203 | +- **Better mobile experience**: Smaller bundles improve performance on slower connections |
| 204 | +- **Production ready**: Size is now within reasonable limits for web deployment |
| 205 | + |
| 206 | +## Caching |
| 207 | + |
| 208 | +Deploy standard industry practices |
| 209 | + |
| 210 | +- **Static Assets:** |
| 211 | + - Uses `Cache-Control: public, max-age=31536000` for 1-year caching. |
| 212 | + - Assets are versioned for cache busting, ensuring users get updates when files change. |
| 213 | +- **API Responses:** |
| 214 | + - Uses `Cache-Control: public, max-age=60` for short-term caching (1 minute). |
| 215 | + - Improves performance for read-only endpoints and reduces database load. |
| 216 | +- **Sensitive/Dynamic Endpoints:** |
| 217 | + - Uses `Cache-Control: no-store` to prevent caching of user actions and sensitive data. |
| 218 | + |
| 219 | +## Future Features |
| 220 | + |
| 221 | +- Centralized Error Handling (**Status**: Planned) |
| 222 | + |
| 223 | +Will add a middleware layer to catch errors, log them, and provide consistent user-friendly responses. Implementation is postponed until the app grows in complexity. |
| 224 | + |
| 225 | +- Modulized global layer (**Status**: Planned) |
| 226 | + |
| 227 | +This was planned out at the begginning with `tower` crate 's ServiceBuilder as a global layer which is then called into server.rs. |
| 228 | + |
| 229 | +However, refactoring this seperated out from server.rs run is more troublesome than expected. |
| 230 | + |
| 231 | +Until the project expands further, it is placed directly in server.rs. |
43 | 232 |
|
44 | 233 | ## Reference |
45 | 234 |
|
46 | 235 | - Book [FullStack Rust with Axum from Martin Fabio](https://www.amazon.com/FullStack-Rust-Axum-Server-Rendered-High-Performance-ebook/dp/B0FM6XF8YX) |
47 | 236 | - [Leptos resources](https://leptos.dev/) |
48 | 237 | - [awesome-leptos repo](https://github.com/leptos-rs/awesome-leptos) |
49 | 238 | - The wild internet, AIs and various other sources... |
50 | | - |
51 | | -## Reflection |
52 | | - |
53 | | -A personal reflection on this project can be found [on this blog post](https://williannguyen.com/posts/4). |
|
0 commit comments