().cloned();
+ }
+
+ to_search.extend(child.children.clone());
+ }
+ }
+
+ None
+ }
}
/// Provides a context value of type `T` to the current reactive [`Owner`]
diff --git a/router/Cargo.toml b/router/Cargo.toml
index 1eae19287..8468e7e2c 100644
--- a/router/Cargo.toml
+++ b/router/Cargo.toml
@@ -28,6 +28,7 @@ send_wrapper = "0.6.0"
thiserror = "1.0"
percent-encoding = { version = "2.3", optional = true }
gloo-net = "0.6.0"
+serde = { version = "1", features = ["derive"] }
[dependencies.web-sys]
version = "0.3.70"
diff --git a/router/src/components.rs b/router/src/components.rs
index 28f2ebef1..6fb2505a0 100644
--- a/router/src/components.rs
+++ b/router/src/components.rs
@@ -450,6 +450,12 @@ pub fn Redirect(
"Calling without a ServerRedirectFunction \
provided, in SSR mode."
);
+
+ #[cfg(not(feature = "tracing"))]
+ eprintln!(
+ "Calling without a ServerRedirectFunction \
+ provided, in SSR mode."
+ );
return;
}
let navigate = use_navigate();
diff --git a/router/src/flat_router.rs b/router/src/flat_router.rs
index 99aa72a9c..53b5cf304 100644
--- a/router/src/flat_router.rs
+++ b/router/src/flat_router.rs
@@ -2,8 +2,8 @@ use crate::{
location::{LocationProvider, Url},
matching::Routes,
params::ParamsMap,
- ChooseView, MatchInterface, MatchNestedRoutes, MatchParams, Method,
- PathSegment, RouteList, RouteListing, RouteMatchId,
+ ChooseView, MatchInterface, MatchNestedRoutes, MatchParams, PathSegment,
+ RouteList, RouteListing, RouteMatchId,
};
use any_spawner::Executor;
use either_of::{Either, EitherOf3};
@@ -511,10 +511,8 @@ where
RouteListing::new(
path,
data.ssr_mode,
- // TODO methods
- [Method::Get],
- // TODO static data
- None,
+ data.methods,
+ data.regenerate,
)
})
.collect::>();
diff --git a/router/src/generate_route_list.rs b/router/src/generate_route_list.rs
index fa3292045..ac305f2ec 100644
--- a/router/src/generate_route_list.rs
+++ b/router/src/generate_route_list.rs
@@ -1,9 +1,17 @@
use crate::{
- matching::PathSegment, Method, SsrMode, StaticDataMap, StaticMode,
+ matching::PathSegment,
+ static_routes::{
+ RegenerationFn, ResolvedStaticPath, StaticPath, StaticRoute,
+ },
+ Method, SsrMode,
};
+use futures::future::join_all;
+use reactive_graph::owner::Owner;
use std::{
cell::{Cell, RefCell},
collections::HashSet,
+ future::Future,
+ mem,
};
use tachys::{renderer::Renderer, view::RenderHtml};
@@ -13,7 +21,7 @@ pub struct RouteListing {
path: Vec,
mode: SsrMode,
methods: HashSet,
- static_mode: Option<(StaticMode, StaticDataMap)>,
+ regenerate: Vec,
}
impl RouteListing {
@@ -22,19 +30,19 @@ impl RouteListing {
path: impl IntoIterator- ,
mode: SsrMode,
methods: impl IntoIterator
- ,
- static_mode: Option<(StaticMode, StaticDataMap)>,
+ regenerate: impl IntoIterator
- ,
) -> Self {
Self {
path: path.into_iter().collect(),
mode,
methods: methods.into_iter().collect(),
- static_mode,
+ regenerate: regenerate.into_iter().collect(),
}
}
/// Create a route listing from a path, with the other fields set to default values.
pub fn from_path(path: impl IntoIterator
- ) -> Self {
- Self::new(path, SsrMode::Async, [], None)
+ Self::new(path, SsrMode::Async, [], [])
}
/// The path this route handles.
@@ -43,8 +51,8 @@ impl RouteListing {
}
/// The rendering mode for this path.
- pub fn mode(&self) -> SsrMode {
- self.mode
+ pub fn mode(&self) -> &SsrMode {
+ &self.mode
}
/// The HTTP request methods this path can handle.
@@ -52,56 +60,95 @@ impl RouteListing {
self.methods.iter().copied()
}
- /// Whether this route is statically rendered.
- #[inline(always)]
- pub fn static_mode(&self) -> Option {
- self.static_mode.as_ref().map(|n| n.0)
+ /// The set of regeneration functions that should be applied to this route, if it is statically
+ /// generated (either up front or incrementally).
+ pub fn regenerate(&self) -> &[RegenerationFn] {
+ &self.regenerate
}
/// Whether this route is statically rendered.
#[inline(always)]
- pub fn static_data_map(&self) -> Option<&StaticDataMap> {
- self.static_mode.as_ref().map(|n| &n.1)
+ pub fn static_route(&self) -> Option<&StaticRoute> {
+ match self.mode {
+ SsrMode::Static(ref route) => Some(route),
+ _ => None,
+ }
}
- pub fn into_static_parts(self) -> Option<(StaticMode, StaticDataMap)> {
- self.static_mode
+ pub async fn into_static_paths(self) -> Option> {
+ let params = self.static_route()?.to_prerendered_params().await;
+ Some(StaticPath::new(self.path).into_paths(params))
+ }
+
+ pub async fn generate_static_files(
+ mut self,
+ render_fn: impl Fn(&ResolvedStaticPath) -> Fut + Send + Clone + 'static,
+ writer: impl Fn(&ResolvedStaticPath, &Owner, String) -> WriterFut
+ + Send
+ + Clone
+ + 'static,
+ was_404: impl Fn(&Owner) -> bool + Send + Clone + 'static,
+ ) where
+ Fut: Future