diff --git a/integrations/actix/src/lib.rs b/integrations/actix/src/lib.rs index 35b4127..758066d 100644 --- a/integrations/actix/src/lib.rs +++ b/integrations/actix/src/lib.rs @@ -282,109 +282,122 @@ where } }; - // Because wasm-pack adds _bg to the end of the WASM filename, and we want to mantain compatibility with it's default options - // we add _bg to the wasm files if cargo-leptos doesn't set the env var LEPTOS_OUTPUT_NAME - // Otherwise we need to add _bg because wasm_pack always does. This is not the same as options.output_name, which is set regardless - let output_name = &options.output_name; - let mut wasm_output_name = output_name.clone(); - if std::env::var("LEPTOS_OUTPUT_NAME").is_err() { - wasm_output_name.push_str("_bg"); - } - - let site_ip = &options.site_address.ip().to_string(); - let reload_port = options.reload_port; - let pkg_path = &options.site_pkg_dir; - - let leptos_autoreload = match std::env::var("LEPTOS_WATCH").is_ok() { - true => format!( - r#" - - "# - ), - false => "".to_string(), - }; - - let head = format!( - r#" - - - - - - - - {leptos_autoreload} - "# - ); - let tail = ""; - - let (stream, runtime, _) = render_to_stream_with_prefix_undisposed( - app, - move |cx| { - let head = use_context::(cx) - .map(|meta| meta.dehydrate()) - .unwrap_or_default(); - format!("{head}").into() - }); - - let mut stream = Box::pin(futures::stream::once(async move { head.clone() }) - .chain(stream) - .chain(futures::stream::once(async move { - runtime.dispose(); - tail.to_string() - })) - .map(|html| Ok(web::Bytes::from(html)) as Result)); - - // Get the first, second, and third chunks in the stream, which renders the app shell, and thus allows Resources to run - let first_chunk = stream.next().await; - let second_chunk = stream.next().await; - let third_chunk = stream.next().await; - - let res_options = res_options.0.read().await; - - let (status, mut headers) = (res_options.status, res_options.headers.clone()); - let status = status.unwrap_or_default(); - - let complete_stream = - futures::stream::iter([first_chunk.unwrap(), second_chunk.unwrap(), third_chunk.unwrap()]) - .chain(stream); - let mut res = HttpResponse::Ok().content_type("text/html").streaming( - complete_stream - ); - // Add headers manipulated in the response - for (key, value) in headers.drain(){ - if let Some(key) = key{ - res.headers_mut().append(key, value); - } - }; - // Set status to what is returned in the function - let res_status = res.status_mut(); - *res_status = status; - // Return the response - res + let (head, tail) = html_parts(&options); + stream_app(app, head, tail, res_options).await } }) } +async fn stream_app(app: impl FnOnce(leptos::Scope) -> View + 'static, + head: String, + tail: String, + res_options: ResponseOptions) -> HttpResponse { + let (stream, runtime, _) = render_to_stream_with_prefix_undisposed( + app, + move |cx| { + let head = use_context::(cx) + .map(|meta| meta.dehydrate()) + .unwrap_or_default(); + format!("{head}").into() + }); + + let mut stream = Box::pin(futures::stream::once(async move { head.clone() }) + .chain(stream) + .chain(futures::stream::once(async move { + runtime.dispose(); + tail.to_string() + })) + .map(|html| Ok(web::Bytes::from(html)) as Result)); + + // Get the first, second, and third chunks in the stream, which renders the app shell, and thus allows Resources to run + let first_chunk = stream.next().await; + let second_chunk = stream.next().await; + let third_chunk = stream.next().await; + + let res_options = res_options.0.read().await; + + let (status, mut headers) = (res_options.status, res_options.headers.clone()); + let status = status.unwrap_or_default(); + + let complete_stream = + futures::stream::iter([first_chunk.unwrap(), second_chunk.unwrap(), third_chunk.unwrap()]) + .chain(stream); + let mut res = HttpResponse::Ok().content_type("text/html").streaming( + complete_stream + ); + // Add headers manipulated in the response + for (key, value) in headers.drain(){ + if let Some(key) = key{ + res.headers_mut().append(key, value); + } + }; + // Set status to what is returned in the function + let res_status = res.status_mut(); + *res_status = status; + // Return the response + res +} + +fn html_parts(options: &LeptosOptions) -> (String, String) { + // Because wasm-pack adds _bg to the end of the WASM filename, and we want to mantain compatibility with it's default options + // we add _bg to the wasm files if cargo-leptos doesn't set the env var LEPTOS_OUTPUT_NAME + // Otherwise we need to add _bg because wasm_pack always does. This is not the same as options.output_name, which is set regardless + let output_name = &options.output_name; + let mut wasm_output_name = output_name.clone(); + if std::env::var("LEPTOS_OUTPUT_NAME").is_err() { + wasm_output_name.push_str("_bg"); + } + + let site_ip = &options.site_address.ip().to_string(); + let reload_port = options.reload_port; + let pkg_path = &options.site_pkg_dir; + + let leptos_autoreload = match std::env::var("LEPTOS_WATCH").is_ok() { + true => format!( + r#" + + "# + ), + false => "".to_string(), + }; + + let head = format!( + r#" + + + + + + + + {leptos_autoreload} + "# + ); + let tail = "".to_string(); + + (head, tail) +} + + /// Generates a list of all routes defined in Leptos's Router in your app. We can then use this to automatically /// create routes in Actix's App without having to use wildcard matching or fallbacks. Takes in your root app Element /// as an argument so it can walk you app tree. This version is tailored to generated Actix compatible paths.