incremental.rs 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. //! Exentsions to the incremental renderer to support pre-caching static routes.
  2. use core::pin::Pin;
  3. use std::future::Future;
  4. use std::str::FromStr;
  5. use dioxus::prelude::*;
  6. use dioxus_ssr::incremental::{
  7. IncrementalRenderer, IncrementalRendererError, RenderFreshness, WrapBody,
  8. };
  9. use crate::prelude::*;
  10. /// Pre-cache all static routes.
  11. pub async fn pre_cache_static_routes<Rt, R: WrapBody + Send + Sync>(
  12. renderer: &mut IncrementalRenderer,
  13. wrapper: &R,
  14. ) -> Result<(), IncrementalRendererError>
  15. where
  16. Rt: Routable,
  17. <Rt as FromStr>::Err: std::fmt::Display,
  18. {
  19. for route in Rt::SITE_MAP
  20. .iter()
  21. .flat_map(|seg| seg.flatten().into_iter())
  22. {
  23. // check if this is a static segment
  24. let mut is_static = true;
  25. let mut full_path = String::new();
  26. for segment in &route {
  27. match segment {
  28. SegmentType::Child => {}
  29. SegmentType::Static(s) => {
  30. full_path += "/";
  31. full_path += s;
  32. }
  33. _ => {
  34. // skip routes with any dynamic segments
  35. is_static = false;
  36. break;
  37. }
  38. }
  39. }
  40. if is_static {
  41. match Rt::from_str(&full_path) {
  42. Ok(route) => {
  43. render_route(
  44. renderer,
  45. route,
  46. &mut tokio::io::sink(),
  47. |vdom| {
  48. Box::pin(async move {
  49. let _ = vdom.wait_for_suspense().await;
  50. })
  51. },
  52. wrapper,
  53. )
  54. .await?;
  55. }
  56. Err(e) => {
  57. log::info!("@ route: {}", full_path);
  58. log::error!("Error pre-caching static route: {}", e);
  59. }
  60. }
  61. }
  62. }
  63. Ok(())
  64. }
  65. /// Render a route to a writer.
  66. pub async fn render_route<
  67. R: WrapBody + Send + Sync,
  68. Rt,
  69. W,
  70. F: FnOnce(&mut VirtualDom) -> Pin<Box<dyn Future<Output = ()> + '_>>,
  71. >(
  72. renderer: &mut IncrementalRenderer,
  73. route: Rt,
  74. writer: &mut W,
  75. modify_vdom: F,
  76. wrapper: &R,
  77. ) -> Result<RenderFreshness, IncrementalRendererError>
  78. where
  79. Rt: Routable,
  80. <Rt as FromStr>::Err: std::fmt::Display,
  81. W: tokio::io::AsyncWrite + Unpin + Send,
  82. {
  83. #[inline_props]
  84. fn RenderPath<R>(cx: Scope, path: R) -> Element
  85. where
  86. R: Routable,
  87. <R as FromStr>::Err: std::fmt::Display,
  88. {
  89. let path = path.clone();
  90. render! {
  91. GenericRouter::<R> {
  92. config: || RouterConfig::default().history(MemoryHistory::with_initial_path(path))
  93. }
  94. }
  95. }
  96. renderer
  97. .render(
  98. route.to_string(),
  99. RenderPath,
  100. RenderPathProps { path: route },
  101. writer,
  102. modify_vdom,
  103. wrapper,
  104. )
  105. .await
  106. }