Rustelo/crates/templates/core-lib-template
Jesús Pérez d3a47108af
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 gitignore and fix content
2026-02-08 20:07:09 +00:00
..

Core Lib Template

This is a template crate for the core runtime library using trait-based dependency injection. It replaces the problematic code generation approach with clean, trait-based abstractions.

Key Features

  • Zero Code Generation: No build.rs, no environment variables, no generated code
  • Pure Dependency Injection: Uses traits from the pure traits layer
  • Implementation Freedom: Clone this template and customize as needed
  • No Circular Dependencies: Clean dependency graph through trait abstractions

Architecture

This template follows the new 3-layer architecture:

Layer 1: Pure Traits (../../../traits/)
    ↓
Layer 2: Templates (this template) 
    ↓
Layer 3: Implementation (your cloned crate)

Usage

1. Clone Template

# Clone this template to your implementation
cp -r templates/core-lib-template my-project/crates/core-lib

# Update Cargo.toml with your project name
sed -i 's/core-lib-template/core-lib/' my-project/crates/core-lib/Cargo.toml

2. Implement Providers

Create your concrete implementations:

use core_lib::*;

// Your page provider implementation
struct MyPageProvider {
    components: HashMap<String, MyComponent>,
}

impl PageProvider for MyPageProvider {
    type Component = MyComponent;
    type View = AnyView;
    type Props = ();
    
    fn get_component(&self, id: &str) -> ComponentResult<Self::Component> {
        self.components.get(id)
            .cloned()
            .ok_or_else(|| ComponentError::NotFound(id.to_string()))
    }
    
    fn render_component(
        &self, 
        component: &Self::Component,
        props: Self::Props,
        language: &str
    ) -> ComponentResult<Self::View> {
        // Your rendering logic here
        Ok(component.render(language))
    }
    
    fn list_components(&self) -> Vec<String> {
        self.components.keys().cloned().collect()
    }
}

3. Configure Application

// Create your application context
let page_provider = MyPageProvider::new();
let content_provider = MyContentProvider::new();
let localization_provider = MyLocalizationProvider::new();
let site_config = load_site_config();

let app_context = AppContext::new(
    page_provider,
    content_provider,
    localization_provider,
    site_config,
);

// Create route handler
let language_detector = ConfigurableLanguageDetector::from_site_config(&app_context.site_config);
let route_resolver = GenericRouteResolver::new(app_context.page_provider.clone(), language_detector);

Modules

Core Modules

  • routing: Language detection, route resolution, generic route handling
  • components: Layout providers, component rendering utilities
  • content: Content item types, query builders
  • i18n: Simple localization provider with HashMap storage
  • errors: Comprehensive error handling with user-friendly messages
  • utils: Path utilities, string formatting, configuration builders

Feature Modules (Optional)

Enable via Cargo features:

  • wasm (default): WASM utilities (console, DOM, storage, HTTP)
  • time: Time formatting, timezone handling, duration parsing
  • ids: UUID generation, slug utilities, content ID management
  • content: Content processing utilities
  • i18n: Internationalization helpers

Benefits Over Code Generation

Before (Problematic)

// Generated at build time, hardcoded dependencies
core_lib::generate_client_render_component!();

After (Clean)

// Trait-based, implementation provides concrete types
impl<P: PageProvider> RouteRenderer for ClientRenderer<P> {
    type View = AnyView;
    type Component = P::Component;
    
    fn render_component(&self, component: &Self::Component, ...) -> RoutingResult<Self::View> {
        self.page_provider.render_component(component, (), language)
    }
}

Example Implementation

See the comprehensive tests in each module for usage examples. Here's a minimal setup:

use core_lib::{*, routing::*, components::*, i18n::*};

// 1. Create providers
let mut page_provider = MyPageProvider::new();
page_provider.register_component("index", IndexComponent);
page_provider.register_component("about", AboutComponent);

let mut localization = SimpleLocalizationProvider::new("en".to_string());
localization.add_translation("en".to_string(), "welcome".to_string(), "Welcome".to_string());

// 2. Create language detector from config
let language_detector = ConfigurableLanguageDetector::new(languages, "en".to_string());

// 3. Create route resolver
let route_resolver = GenericRouteResolver::new(page_provider, language_detector);

// 4. Handle requests
let resolution = route_resolver.resolve_route("/about")?;
if let Some(component) = resolution.component {
    let result = route_handler.handle_route(
        Some(&component), 
        &resolution.path, 
        &resolution.language, 
        &resolution.parameters
    )?;
    println!("Rendered: {:?}", result.view);
}

Migration from Foundation

When migrating from the old foundation crate:

  1. Remove build.rs: No more code generation
  2. Replace generated code: Use trait-based providers instead
  3. Inject dependencies: Pass concrete implementations via constructors
  4. Remove environment dependencies: Use configuration objects instead

Features

Configure optional functionality via Cargo features:

[features]
default = ["wasm"]
full = ["wasm", "time", "ids", "content", "i18n"]
minimal = []

Testing

Each module includes comprehensive tests. Run with:

cargo test
cargo test --all-features  # Test with all features enabled
cargo test --no-default-features  # Test minimal configuration

Compatibility

  • Rust 2021 Edition
  • WASM Compatible: Conditional compilation for WASM vs native
  • Feature Gated: Only compile what you need
  • Framework Agnostic: Works with any Leptos application

This template solves the circular dependency and tight coupling issues while maintaining full implementation flexibility through trait-based dependency injection.