Rustelo/docs/howto/creating-a-site.md
Jesús Pérez 98e2d4e783
Some checks failed
CI/CD Pipeline / Test Suite (push) Has been cancelled
CI/CD Pipeline / Security Audit (push) Has been cancelled
CI/CD Pipeline / Build Docker Image (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / Performance Benchmarks (push) Has been cancelled
CI/CD Pipeline / Cleanup (push) Has been cancelled
chore: update docs
2026-02-08 20:12:31 +00:00

13 KiB

Creating a Site with Rustelo Framework

This guide provides step-by-step instructions for creating a new website project using Rustelo as a framework dependency.

🎯 Overview

Rustelo follows a framework-as-dependency architecture, meaning you don't fork the framework - you use it as a library dependency in your own project. This ensures you can:

  • Get framework updates automatically
  • Keep your customizations separate from framework code
  • Use the asset fallback system (Local → Framework → Generated)
  • Avoid maintaining a fork

📋 Prerequisites

  • Rust 1.70+ installed
  • Node.js 18+ (for frontend assets)
  • Just task runner: cargo install just
  • Git (recommended for version control)

🚀 Step-by-Step Guide

Step 1: Create Your Project Directory

# Create your site project
mkdir my-awesome-site
cd my-awesome-site

# Initialize git repository (optional but recommended)
git init

Step 2: Create Cargo.toml

Create a Cargo.toml file with Rustelo dependencies:

[package]
name = "my-awesome-site"
version = "0.1.0"
edition = "2021"
authors = ["Your Name <your.email@example.com>"]
description = "My awesome site built with Rustelo framework"

# Main binary
[[bin]]
name = "server"
path = "src/main.rs"

[dependencies]
# Core Rustelo framework dependencies
rustelo-core = { path = "../rustelo/crates/rustelo-core" }
rustelo-web = { path = "../rustelo/crates/rustelo-web" }

# Optional framework components (uncomment as needed)
# rustelo-auth = { path = "../rustelo/crates/rustelo-auth" }
# rustelo-content = { path = "../rustelo/crates/rustelo-content" }

# Web framework essentials
leptos = { version = "0.8.6", features = ["ssr"] }
leptos_axum = "0.8.5"
axum = "0.8.4"
tokio = { version = "1.47.1", features = ["rt-multi-thread", "signal"] }
tower = "0.5.2"
tower-http = { version = "0.6.6", features = ["fs"] }

# Basic utilities
tracing = "0.1"
tracing-subscriber = "0.3"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

[features]
default = []

# Optional features (enable as needed)
# auth = ["rustelo-auth"]
# content = ["rustelo-content"]
# database = ["rustelo-core/database"]

[profile.release]
codegen-units = 1
lto = true
opt-level = 'z'

# Leptos configuration for development server
[[workspace.metadata.leptos]]
name = "my-awesome-site"
bin-package = "my-awesome-site"
bin-target-path = "src/main.rs"
lib-profile-release = "wasm-release"

Step 3: Create Source Code Structure

# Create source directory
mkdir -p src

# Create basic directory structure
mkdir -p {content,assets,config,justfiles,public}

Step 4: Create Main Application File

Create src/main.rs:

//! My Awesome Site - Built with Rustelo Framework
//! 
//! This demonstrates using Rustelo as a framework dependency for a production site.

use axum::{
    response::Html,
    routing::get,
    Router,
};
use rustelo_core::config::RusteloConfig;
use tower_http::services::ServeDir;
use tracing_subscriber;

/// Home page component
async fn home() -> Html<&'static str> {
    Html(r#"
    <!DOCTYPE html>
    <html>
    <head>
        <title>My Awesome Site</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <style>
            body { 
                font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; 
                max-width: 1200px; 
                margin: 0 auto; 
                padding: 2rem;
                line-height: 1.6;
            }
            .hero { 
                text-align: center; 
                padding: 4rem 0; 
                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                color: white;
                border-radius: 1rem;
                margin-bottom: 3rem;
            }
            .features { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 2rem; }
            .feature { 
                background: #f8fafc; 
                padding: 2rem; 
                border-radius: 0.5rem; 
                border: 1px solid #e2e8f0;
            }
            .feature h3 { color: #2d3748; margin-top: 0; }
            .footer { 
                text-align: center; 
                margin-top: 4rem; 
                padding-top: 2rem; 
                border-top: 1px solid #e2e8f0;
                color: #718096;
            }
        </style>
    </head>
    <body>
        <div class="hero">
            <h1>🌟 My Awesome Site</h1>
            <p>Built with Rustelo Framework-as-Dependency Architecture</p>
        </div>
        
        <div class="features">
            <div class="feature">
                <h3>🦀 Framework-as-Dependency</h3>
                <p>Uses Rustelo as a library dependency, not a fork. Get framework updates automatically while keeping your customizations.</p>
            </div>
            
            <div class="feature">
                <h3>📁 Asset Fallback System</h3>
                <p>Local → Framework → Generated priority resolution. Override any framework asset with your local version.</p>
            </div>
            
            <div class="feature">
                <h3>🔧 Modular Features</h3>
                <p>Enable only the framework features you need: authentication, content management, database support, etc.</p>
            </div>
            
            <div class="feature">
                <h3>🚀 Production Ready</h3>
                <p>Built on Leptos + Axum with SSR, optimized builds, and cross-compilation support.</p>
            </div>
        </div>
        
        <div class="footer">
            <p><em>Powered by Rustelo Framework • <a href="/api/status">API Status</a></em></p>
        </div>
    </body>
    </html>
    "#)
}

/// About page
async fn about() -> Html<&'static str> {
    Html(r#"
    <!DOCTYPE html>
    <html>
    <head>
        <title>About - My Awesome Site</title>
        <style>
            body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 2rem; }
            .nav { margin-bottom: 2rem; }
            .nav a { margin-right: 1rem; text-decoration: none; color: #2563eb; }
        </style>
    </head>
    <body>
        <div class="nav">
            <a href="/">Home</a>
            <a href="/about">About</a>
            <a href="/api/status">API</a>
        </div>
        <h1>About My Awesome Site</h1>
        <p>This site demonstrates the Rustelo framework-as-dependency architecture.</p>
        <p>Key benefits:</p>
        <ul>
            <li>No source code forking required</li>
            <li>Automatic framework updates</li>
            <li>Local asset overrides</li>
            <li>Modular feature system</li>
        </ul>
    </body>
    </html>
    "#)
}

/// API endpoint showing framework integration
async fn api_status() -> axum::Json<serde_json::Value> {
    axum::Json(serde_json::json!({
        "status": "ok",
        "framework": "rustelo",
        "architecture": "framework-as-dependency",
        "features": {
            "core": true,
            "web": true,
            "auth": false,
            "content": false
        },
        "message": "🎉 Framework-as-dependency architecture working!"
    }))
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Initialize logging
    tracing_subscriber::fmt()
        .with_target(false)
        .init();

    tracing::info!("🚀 Starting My Awesome Site...");

    // Load framework configuration (with defaults if no config file exists)
    let _config = RusteloConfig::load().unwrap_or_default();
    
    tracing::info!("📋 Framework configuration loaded");

    // Build application routes
    let app = Router::new()
        .route("/", get(home))
        .route("/about", get(about))
        .route("/api/status", get(api_status))
        // Serve static files if they exist
        .nest_service("/static", ServeDir::new("public"))
        .nest_service("/assets", ServeDir::new("assets"))
        .with_state(());

    // Start server
    let addr = "127.0.0.1:3030";
    tracing::info!("🌐 Server starting at http://{}", addr);
    tracing::info!("✨ Framework-as-dependency architecture active!");

    let listener = tokio::net::TcpListener::bind(addr).await?;
    axum::serve(listener, app).await?;

    Ok(())
}

Step 5: Create Framework Configuration (Optional)

Create rustelo.toml for framework configuration:

[framework]
name = "my-awesome-site"
version = "0.1.0"
description = "My awesome site built with Rustelo"

[assets]
# Asset resolution configuration
local_path = "assets"
framework_path = "../rustelo/assets"
organize_by_category = false

[server]
host = "127.0.0.1"
port = 3030
enable_tls = false

[features]
# Enable framework features as needed
auth = false
content = false
database = false

Step 6: Create Justfile for Task Management

Create justfile with framework fallback pattern:

# My Awesome Site - Task Runner with Framework Fallback
# Local tasks take priority, framework tasks as fallback

# Try to import local tasks, then framework tasks
mod? local-base 'justfiles/base.just'                    # Local base tasks
mod? base '../rustelo/justfiles/base.just'              # Framework fallback

# Local development server
dev:
    @echo "🚀 Starting development server..."
    cargo run --bin server

# Local build
build mode="release":
    @echo "🔨 Building for {{mode}} mode..."
    @if [ "{{mode}}" = "release" ]; then \
        cargo build --release; \
    else \
        cargo build; \
    fi

# Local test
test:
    @echo "🧪 Running tests..."
    cargo test

# Local clean
clean:
    @echo "🧹 Cleaning build artifacts..."
    cargo clean
    rm -rf target/

# Check code quality
check:
    @echo "🔍 Checking code quality..."
    cargo check
    cargo clippy
    cargo fmt --check

# Format code
fmt:
    @echo "✨ Formatting code..."
    cargo fmt

# Install dependencies
deps:
    @echo "📦 Installing dependencies..."
    cargo fetch

# Show available tasks
help:
    @echo "Available tasks:"
    @just --list

Step 7: Create Local Justfile Tasks (Optional)

Create justfiles/base.just for site-specific tasks:

# Local base tasks for My Awesome Site

# Custom deploy task
deploy:
    @echo "🚀 Deploying My Awesome Site..."
    just build release
    # Add your deployment commands here

# Custom content tasks
content-update:
    @echo "📝 Updating content..."
    # Add content management commands here

# Custom asset processing
assets-build:
    @echo "🎨 Processing assets..."
    # Add asset processing commands here

Step 8: Run Your Site

# Run development server
just dev

# Or run directly with cargo
cargo run --bin server

# Visit http://127.0.0.1:3030

🔧 Customization Options

Enable Framework Features

Uncomment features in Cargo.toml as needed:

# Enable authentication
rustelo-auth = { path = "../rustelo/crates/rustelo-auth" }

# Enable content management  
rustelo-content = { path = "../rustelo/crates/rustelo-content" }

[features]
auth = ["rustelo-auth"]
content = ["rustelo-content"]
database = ["rustelo-core/database"]

Asset Fallback System

  1. Local Assets: Place in assets/ - highest priority
  2. Framework Assets: Automatic fallback to framework assets
  3. Generated Assets: Created by build system if needed

Override Framework Justfile Tasks

Create justfiles/base.just with your custom tasks to override framework defaults.

📁 Final Project Structure

my-awesome-site/
├── Cargo.toml              # Dependencies and configuration
├── rustelo.toml            # Framework configuration (optional)
├── justfile                # Task runner with framework fallback
├── src/
│   └── main.rs             # Main application
├── justfiles/              # Local task overrides
│   └── base.just           # Custom tasks
├── assets/                 # Local assets (override framework)
├── content/                # Site content
├── config/                 # Configuration files
├── public/                 # Static public files
└── target/                 # Build output

🚀 Next Steps

  1. Add Content: Create pages in src/ or use rustelo-content crate
  2. Style Your Site: Add CSS in assets/ or public/
  3. Enable Features: Add authentication, database, etc.
  4. Deploy: Use just deploy or your preferred deployment method
  5. Update Framework: cargo update gets latest framework versions

Benefits Achieved

  • No fork required - Pure dependency usage
  • Framework updates - Automatic via cargo update
  • Local customization - Override any framework asset
  • Asset fallback - Local → Framework → Generated
  • Modular features - Enable only what you need
  • Production ready - Optimized builds and deployment

This approach ensures you have a maintainable, updatable website that leverages the Rustelo framework without becoming dependent on a fork!