Require every field in router variants to be present in the route in the web history (#2159)

* require every field to be present in the URL in the web history

* remove desktop only extra field from the simple routes example
This commit is contained in:
Evan Almloff authored and GitHub committed 2024-03-27 18:12:35 -07:00
1 parent 329c323b35
commit e8491d5cf4
4 files changed
+42 -7

No files matched your search

+1
View File
@@ -22,3 +22,4 @@ slab = { workspace = true }
[features] [features]
default = [] default = []
web = []
+38 -1
View File
@@ -62,7 +62,6 @@ mod segment;
/// user_id: usize, /// user_id: usize,
/// dynamic: usize, /// dynamic: usize,
/// query: String, /// query: String,
/// extra: String,
/// }, /// },
/// #[route("/hello_world")] /// #[route("/hello_world")]
/// // You can opt out of the layout by using the `!` prefix /// // You can opt out of the layout by using the `!` prefix
@@ -437,9 +436,47 @@ impl RouteEnum {
site_map, site_map,
}; };
// If we're on the web, only the URL history is preserved between navigation. We need to warn the user that the segment is not present in the URL.
if cfg!(feature = "web") {
for variant in &data.variants {
for field in &variant.fields {
if !myself.field_present_in_url(field.ident.as_ref().unwrap()) {
return Err(syn::Error::new_spanned(
field.ident.as_ref().unwrap(),
format!("The `{}` field must be present in the url for the web history. You can include the field in the url by using the `#[route(\"/:{}\")]` attribute on the enum variant.", field.ident.as_ref().unwrap(), field.ident.as_ref().unwrap()),
));
}
}
}
}
Ok(myself) Ok(myself)
} }
fn field_present_in_url(&self, field: &Ident) -> bool {
let mut from_route = false;
for nest in &self.nests {
if nest.dynamic_segments_names().any(|i| &i == field) {
from_route = true
}
}
for route in &self.routes {
for segment in &route.segments {
if segment.name().as_ref() == Some(field) {
from_route = true
}
}
if let Some(query) = &route.query {
if query.contains_ident(field) {
from_route = true
}
}
}
from_route
}
fn impl_display(&self) -> TokenStream2 { fn impl_display(&self) -> TokenStream2 {
let mut display_match = Vec::new(); let mut display_match = Vec::new();
+1 -2
View File
@@ -35,7 +35,7 @@ default = []
ssr = ["dioxus-ssr/incremental", "tokio", "dioxus-fullstack?/server"] ssr = ["dioxus-ssr/incremental", "tokio", "dioxus-fullstack?/server"]
liveview = ["dioxus-liveview", "tokio", "dep:serde", "serde_json"] liveview = ["dioxus-liveview", "tokio", "dep:serde", "serde_json"]
wasm_test = [] wasm_test = []
web = ["gloo", "web-sys", "wasm-bindgen", "gloo-utils", "js-sys"] web = ["gloo", "web-sys", "wasm-bindgen", "gloo-utils", "js-sys", "dioxus-router-macro/web"]
fullstack = ["dioxus-fullstack"] fullstack = ["dioxus-fullstack"]
[dev-dependencies] [dev-dependencies]
@@ -54,7 +54,6 @@ name = "incremental"
required-features = ["ssr"] required-features = ["ssr"]
harness = false harness = false
# you need to comment this out when publishing since cargo workspaces is not smart enough to wipe this when dropping # you need to comment this out when publishing since cargo workspaces is not smart enough to wipe this when dropping
# dev-dependncey crates # dev-dependncey crates
[target.'cfg(target_family = "wasm")'.dev-dependencies] [target.'cfg(target_family = "wasm")'.dev-dependencies]
+2 -4
View File
@@ -65,17 +65,16 @@ fn UserFrame(user_id: usize) -> Element {
} }
#[component] #[component]
fn Route1(user_id: usize, dynamic: usize, query: String, extra: String) -> Element { fn Route1(user_id: usize, dynamic: usize, query: String) -> Element {
rsx! { rsx! {
pre { pre {
"Route1{{\n\tuser_id:{user_id},\n\tdynamic:{dynamic},\n\tquery:{query},\n\textra:{extra}\n}}" "Route1{{\n\tuser_id:{user_id},\n\tdynamic:{dynamic},\n\tquery:{query}\n}}"
} }
Link { Link {
to: Route::Route1 { to: Route::Route1 {
user_id, user_id,
dynamic, dynamic,
query: String::new(), query: String::new(),
extra: extra.clone() + ".",
}, },
"Route1 with extra+\".\"" "Route1 with extra+\".\""
} }
@@ -191,7 +190,6 @@ enum Route {
user_id: usize, user_id: usize,
dynamic: usize, dynamic: usize,
query: String, query: String,
extra: String,
}, },
#[route("/hello_world")] #[route("/hello_world")]
// You can opt out of the layout by using the `!` prefix // You can opt out of the layout by using the `!` prefix