diff --git a/Cargo.toml b/Cargo.toml index aed64c1..aea60f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,4 +11,3 @@ regex = "1.10.5" nanoid = "0.4.0" indoc = "2.0.5" lru = "0.12.3" -tracing = "0.1.40" diff --git a/src/island.rs b/src/island.rs index 7c72177..d25ca75 100644 --- a/src/island.rs +++ b/src/island.rs @@ -1,3 +1,5 @@ +use crate::config::SsrkitConfig; +use lru::LruCache; use nanoid::nanoid; use serde_json::Value; use std::borrow::Cow; @@ -62,7 +64,6 @@ impl IslandManifest { pub struct ProcessContext { pub path: String, - // 可以根据需要添加更多字段 } pub trait IslandProcessor: Send + Sync { @@ -183,19 +184,28 @@ impl Clone for IslandManager { } } -static ISLAND_CACHE: OnceLock>> = OnceLock::new(); +static ISLAND_CACHE: OnceLock>> = OnceLock::new(); +static CONFIG: OnceLock = OnceLock::new(); + +pub fn init_island_cache(config: &SsrkitConfig) { + let _ = CONFIG.set(config.clone()); +} pub fn get_or_render_island(key: &str, render_fn: F) -> String where F: FnOnce() -> String, { - let cache = ISLAND_CACHE.get_or_init(|| Mutex::new(HashMap::new())); + let cache = ISLAND_CACHE.get_or_init(|| { + let binding = SsrkitConfig::default(); + let config = CONFIG.get().unwrap_or(&binding); + Mutex::new(LruCache::new(config.island_cache_size)) + }); let mut cache_guard = cache.lock().unwrap(); match cache_guard.get(key) { Some(cached) => cached.clone(), None => { let rendered = render_fn(); - cache_guard.insert(key.to_string(), rendered.clone()); + cache_guard.put(key.to_string(), rendered.clone()); rendered } } diff --git a/src/lib.rs b/src/lib.rs index b7cf04c..8bcacf0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,12 +2,14 @@ pub mod island; pub mod params; pub mod render; pub mod template; +pub mod config; // Re-export main types and traits pub use island::{CombinedIslandProcessor, IslandManager, IslandProcessor, ProcessContext, get_or_render_island}; pub use params::{CombinedParamsProcessor, ParamsProcessor}; pub use render::{init_ssr, SsrRenderer, get_renderer}; pub use template::Template; +pub use config::SsrkitConfig; // Re-export important types from serde_json that are commonly used pub use serde_json::{Map, Value}; @@ -18,11 +20,6 @@ pub mod prelude { pub use crate::params::{CombinedParamsProcessor, ParamsProcessor}; pub use crate::render::{init_ssr, SsrRenderer, get_renderer}; pub use crate::template::Template; + pub use crate::config::SsrkitConfig; pub use serde_json::{Map, Value}; -} - -// If you have any error types, you might want to re-export them here -// pub use crate::error::SsrKitError; - -// If you have any configuration structs, you might want to re-export them here -// pub use crate::config::SsrKitConfig; \ No newline at end of file +} \ No newline at end of file diff --git a/src/render.rs b/src/render.rs index adb11fa..bb71528 100644 --- a/src/render.rs +++ b/src/render.rs @@ -1,12 +1,12 @@ -use crate::island::{IslandManager, IslandProcessor, ProcessContext}; +use crate::island::{init_island_cache, IslandManager, IslandProcessor, ProcessContext}; use crate::params::ParamsProcessor; -use crate::template::Template; +use crate::template::{init_template_cache, Template}; +use crate::SsrkitConfig; use regex::Regex; use serde_json::{json, Value}; use std::collections::HashMap; use std::sync::Arc; use std::sync::OnceLock; -use tracing::{info, instrument}; // 全局靜態變量 static ISLAND_REGEX: OnceLock = OnceLock::new(); @@ -21,7 +21,6 @@ pub struct SsrRenderer { } impl SsrRenderer { - #[instrument(skip(params_processor, island_manager, template))] fn new( params_processor: Box, island_manager: Arc, @@ -34,7 +33,6 @@ impl SsrRenderer { } } - #[instrument(skip(self, params, render_fn), fields(path = %path))] pub fn render( &self, path: &str, @@ -45,7 +43,6 @@ impl SsrRenderer { F: FnOnce(&str) -> Result, { let processed_params = self.params_processor.process(path, ¶ms); - info!("Params processed"); let props = serde_json::json!({ "url": path, @@ -53,23 +50,18 @@ impl SsrRenderer { }); let content = render_fn(&props.to_string())?; - info!("Render function called"); let mut rendered = serde_json::from_str::(&content) .map_err(|e| format!("Failed to parse render result: {}", e))?; - info!("Render result parsed"); // 條件性島嶼處理 let mut used_islands = Vec::new(); if let Some(html) = rendered["html"].as_str() { if html.contains("data-island") { - info!("Islands detected, starting replacement"); let (replaced_html, islands) = self.replace_island_placeholders(html)?; rendered["html"] = Value::String(replaced_html); used_islands = islands; - info!("Islands replaced"); } else { - info!("No islands detected, skipping replacement"); } } @@ -83,11 +75,9 @@ impl SsrRenderer { }; let result = self.template.render(&rendered, &islands_json); - info!("Template rendered"); result } - #[instrument(skip(self, html))] fn replace_island_placeholders(&self, html: &str) -> Result<(String, Vec), String> { let re = ISLAND_REGEX.get().expect("Regex not initialized"); let mut result = html.to_string(); @@ -103,7 +93,6 @@ impl SsrRenderer { let rendered_island = self.island_manager.render_island(island_id, &props)?; result = result.replace(&cap[0], &rendered_island); used_islands.push(island_id.to_string()); - info!("Island rendered: {}", island_id); } Ok((result, used_islands)) @@ -138,22 +127,28 @@ impl SsrRenderer { } } -#[instrument(skip(params_processor_init, island_manager_init, template_init))] pub fn init_ssr( params_processor_init: impl FnOnce() -> Box, island_manager_init: impl FnOnce() -> IslandManager, template_init: impl FnOnce() -> Template, + config: Option<&SsrkitConfig>, ) { + let config = config.cloned().unwrap_or_default(); + // 初始化正則表達式 ISLAND_REGEX.get_or_init(|| { Regex::new(r#"
"#).unwrap() }); // 初始化 IslandManager - ISLAND_MANAGER.get_or_init(|| Arc::new(island_manager_init())); + let island_manager = island_manager_init(); + init_island_cache(&config); + ISLAND_MANAGER.get_or_init(|| Arc::new(island_manager)); // 初始化 Template - TEMPLATE.get_or_init(|| Arc::new(template_init())); + let template = template_init(); + init_template_cache(&config); + TEMPLATE.get_or_init(|| Arc::new(template)); // 初始化 Renderer RENDERER.get_or_init(|| { @@ -164,7 +159,6 @@ pub fn init_ssr( ) }); - info!("SSR components initialized"); } pub fn get_renderer() -> &'static SsrRenderer { diff --git a/src/template.rs b/src/template.rs index cb47a02..2a12b9f 100644 --- a/src/template.rs +++ b/src/template.rs @@ -1,15 +1,22 @@ +use crate::config::SsrkitConfig; +use lru::LruCache; use serde_json::Value; use std::collections::HashSet; use std::sync::OnceLock; use std::sync::Mutex; -use lru::LruCache; -use std::num::NonZeroUsize; static TEMPLATE_CACHE: OnceLock>> = OnceLock::new(); +static CONFIG: OnceLock = OnceLock::new(); + +pub fn init_template_cache(config: &SsrkitConfig) { + let _ = CONFIG.set(config.clone()); +} fn get_cache() -> &'static Mutex> { TEMPLATE_CACHE.get_or_init(|| { - Mutex::new(LruCache::new(NonZeroUsize::new(100).unwrap())) + let binding = SsrkitConfig::default(); + let config = CONFIG.get().unwrap_or(&binding); + Mutex::new(LruCache::new(config.template_cache_size)) }) } @@ -23,7 +30,7 @@ impl Template { pub fn render(&self, content: &Value, islands: &Value) -> Result { let cache_key = format!("{:?}:{:?}", content, islands); - // 嘗試從緩存中獲取 + // Try to get from cache if let Some(cached_html) = get_cache().lock().unwrap().get(&cache_key) { return Ok(cached_html.clone()); } @@ -36,22 +43,22 @@ impl Template { let island_scripts = self.generate_island_scripts(islands); let rendered_html = if html.trim().starts_with("") || html.trim().starts_with("") { - // 如果是完整的 HTML,我們只需要插入額外的內容 + // If it's a complete HTML, we just need to insert extra content let mut rendered_html = html.to_string(); - // 在 之前插入額外的頭部內容 + // Insert extra head content before if let Some(head_end) = rendered_html.find("") { rendered_html.insert_str(head_end, &format!("{}{}", head_extra, css, island_scripts)); } - // 在 之後插入額外的身體內容 + // Insert extra body content after if let Some(body_start) = rendered_html.find("") { rendered_html.insert_str(body_start + 6, body_extra); } rendered_html } else { - // 如果不是完整的 HTML,使用我們的模板 + // If it's not a complete HTML, use our template indoc::formatdoc! {r#" @@ -71,7 +78,7 @@ impl Template { let mut final_html = rendered_html; self.replace_island_placeholders(&mut final_html, islands); - // 將結果存入緩存 + // Store result in cache get_cache().lock().unwrap().put(cache_key, final_html.clone()); Ok(final_html)