@@ -22,25 +22,54 @@ use url::Url;
2222use crate :: app:: AppState ;
2323
2424const OG_IMAGE_FALLBACK_URL : & str = "https://crates.io/assets/og-image.png" ;
25- const INDEX_TEMPLATE_NAME : & str = "index_html" ;
2625const PATH_PREFIX_CRATES : & str = "/crates/" ;
2726
27+ #[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash ) ]
28+ enum FrontendApp {
29+ Ember ,
30+ Svelte ,
31+ }
32+
33+ impl FrontendApp {
34+ fn from_path ( path : & str ) -> Self {
35+ if path. starts_with ( "/svelte/" ) {
36+ FrontendApp :: Svelte
37+ } else {
38+ FrontendApp :: Ember
39+ }
40+ }
41+
42+ fn index_template_name ( & self ) -> & ' static str {
43+ match self {
44+ FrontendApp :: Ember => "index_html" ,
45+ FrontendApp :: Svelte => "svelte_index_html" ,
46+ }
47+ }
48+ }
49+
2850/// The [`Shared`] allows for multiple tasks to wait on a single future, [`BoxFuture`] allows
2951/// us to name the type in the declaration of static variables, and the [`Arc`] ensures
3052/// the [`minijinja::Environment`] doesn't get cloned each request.
3153type TemplateEnvFut = Shared < BoxFuture < ' static , Arc < minijinja:: Environment < ' static > > > > ;
32- type TemplateCache = moka:: future:: Cache < Cow < ' static , str > , String > ;
54+ type TemplateCache = moka:: future:: Cache < ( Cow < ' static , str > , FrontendApp ) , String > ;
3355
3456/// Initialize [`minijinja::Environment`] given the index.html file at `dist/index.html`.
3557/// This should only be done once as it will load said file from persistent storage.
3658async fn init_template_env ( ) -> Arc < minijinja:: Environment < ' static > > {
59+ let mut env = minijinja:: Environment :: empty ( ) ;
60+
3761 let template_j2 = tokio:: fs:: read_to_string ( "dist/index.html" )
3862 . await
3963 . expect ( "Error loading dist/index.html template. Is the frontend package built yet?" ) ;
4064
41- let mut env = minijinja:: Environment :: empty ( ) ;
42- env. add_template_owned ( INDEX_TEMPLATE_NAME , template_j2)
65+ env. add_template_owned ( FrontendApp :: Ember . index_template_name ( ) , template_j2)
4366 . expect ( "Error loading template" ) ;
67+
68+ if let Ok ( svelte_template) = tokio:: fs:: read_to_string ( "svelte/build/200.html" ) . await {
69+ env. add_template_owned ( FrontendApp :: Svelte . index_template_name ( ) , svelte_template)
70+ . expect ( "Error loading Svelte template" ) ;
71+ }
72+
4473 Arc :: new ( env)
4574}
4675
@@ -83,8 +112,10 @@ pub async fn serve_html(state: AppState, request: Request, next: Next) -> Respon
83112 let html_cache = RENDERED_HTML_CACHE
84113 . get_or_init ( || init_html_cache ( state. config . html_render_cache_max_capacity ) ) ;
85114
115+ let frontend_app = FrontendApp :: from_path ( path) ;
116+
86117 let render_result = html_cache
87- . entry_by_ref ( & og_image_url)
118+ . entry_by_ref ( & ( og_image_url. clone ( ) , frontend_app ) )
88119 . or_try_insert_with :: < _ , minijinja:: Error > ( async {
89120 // `LazyLock::deref` blocks as long as its initializer is running in another thread.
90121 // Note that this won't take long, as the constructed Futures are not awaited
@@ -94,7 +125,7 @@ pub async fn serve_html(state: AppState, request: Request, next: Next) -> Respon
94125 // Render the HTML given the OG image URL
95126 let env = template_env. clone ( ) . await ;
96127 let html = env
97- . get_template ( INDEX_TEMPLATE_NAME ) ?
128+ . get_template ( frontend_app . index_template_name ( ) ) ?
98129 . render ( minijinja:: context! { og_image_url} ) ?;
99130
100131 Ok ( html)
0 commit comments