Forráskód Böngészése

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
Evan Almloff 1 éve
szülő
commit
e8491d5cf4

+ 1 - 0
packages/router-macro/Cargo.toml

@@ -22,3 +22,4 @@ slab = { workspace = true }
 
 [features]
 default = []
+web = []

+ 38 - 1
packages/router-macro/src/lib.rs

@@ -62,7 +62,6 @@ mod segment;
 ///                 user_id: usize,
 ///                 dynamic: usize,
 ///                 query: String,
-///                 extra: String,
 ///             },
 ///             #[route("/hello_world")]
 ///             // You can opt out of the layout by using the `!` prefix
@@ -437,9 +436,47 @@ impl RouteEnum {
             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)
     }
 
+    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 {
         let mut display_match = Vec::new();
 

+ 1 - 2
packages/router/Cargo.toml

@@ -35,7 +35,7 @@ default = []
 ssr = ["dioxus-ssr/incremental", "tokio", "dioxus-fullstack?/server"]
 liveview = ["dioxus-liveview", "tokio", "dep:serde", "serde_json"]
 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"]
 
 [dev-dependencies]
@@ -54,7 +54,6 @@ name = "incremental"
 required-features = ["ssr"]
 harness = false
 
-
 # you need to comment this out when publishing since cargo workspaces is not smart enough to wipe this when dropping
 # dev-dependncey crates
 [target.'cfg(target_family = "wasm")'.dev-dependencies]

+ 2 - 4
packages/router/examples/simple_routes.rs

@@ -65,17 +65,16 @@ fn UserFrame(user_id: usize) -> Element {
 }
 
 #[component]
-fn Route1(user_id: usize, dynamic: usize, query: String, extra: String) -> Element {
+fn Route1(user_id: usize, dynamic: usize, query: String) -> Element {
     rsx! {
         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 {
             to: Route::Route1 {
                 user_id,
                 dynamic,
                 query: String::new(),
-                extra: extra.clone() + ".",
             },
             "Route1 with extra+\".\""
         }
@@ -191,7 +190,6 @@ enum Route {
                     user_id: usize,
                     dynamic: usize,
                     query: String,
-                    extra: String,
                 },
                 #[route("/hello_world")]
                 // You can opt out of the layout by using the `!` prefix