ソースを参照

Fix flakey windows tests (#2332)

Evan Almloff 1 年間 前
コミット
5ce91e1bfc

+ 3 - 0
Cargo.lock

@@ -2371,6 +2371,7 @@ dependencies = [
  "base64 0.21.7",
  "bytes",
  "ciborium",
+ "dioxus",
  "dioxus-cli-config",
  "dioxus-desktop",
  "dioxus-hot-reload",
@@ -2488,6 +2489,7 @@ dependencies = [
 name = "dioxus-lib"
 version = "0.5.2"
 dependencies = [
+ "dioxus",
  "dioxus-config-macro",
  "dioxus-core 0.5.2",
  "dioxus-core-macro",
@@ -2603,6 +2605,7 @@ dependencies = [
 name = "dioxus-router-macro"
 version = "0.5.2"
 dependencies = [
+ "dioxus",
  "proc-macro2",
  "quote",
  "slab",

+ 12 - 3
Makefile.toml

@@ -88,7 +88,7 @@ command = "cargo"
 args = ["build"]
 
 [tasks.test-flow]
-dependencies = ["test"]
+dependencies = ["test", "docs"]
 private = true
 
 [tasks.test]
@@ -101,8 +101,7 @@ args = [
   "--tests",
   "--examples",
   "--workspace",
-  "--exclude",
-  "dioxus-router",
+  # These tests run on Ubuntu without a screen. Desktop tests that require a screen fail, so we skip them
   "--exclude",
   "dioxus-desktop",
   "--exclude",
@@ -110,6 +109,16 @@ args = [
 ]
 private = true
 
+[tasks.docs]
+dependencies = ["build"]
+command = "cargo"
+args = [
+  "test",
+  "--doc",
+  "--workspace",
+]
+private = true
+
 [tasks.test-with-browser]
 env = { CARGO_MAKE_WORKSPACE_INCLUDE_MEMBERS = [
   "**/packages/router",

+ 43 - 36
examples/todomvc.rs

@@ -1,7 +1,6 @@
 //! The typical TodoMVC app, implemented in Dioxus.
 
 use dioxus::prelude::*;
-use dioxus_elements::input_data::keyboard_types::Key;
 use std::collections::HashMap;
 
 fn main() {
@@ -74,7 +73,7 @@ fn app() -> Element {
                         class: "toggle-all",
                         r#type: "checkbox",
                         onchange: toggle_all,
-                        checked: active_todo_count() == 0,
+                        checked: active_todo_count() == 0
                     }
                     label { r#for: "toggle-all" }
                 }
@@ -98,8 +97,14 @@ fn app() -> Element {
         // A simple info footer
         footer { class: "info",
             p { "Double-click to edit a todo" }
-            p { "Created by " a { href: "http://github.com/jkelleyrtp/", "jkelleyrtp" } }
-            p { "Part of " a { href: "http://todomvc.com", "TodoMVC" } }
+            p {
+                "Created by "
+                a { href: "http://github.com/jkelleyrtp/", "jkelleyrtp" }
+            }
+            p {
+                "Part of "
+                a { href: "http://todomvc.com", "TodoMVC" }
+            }
         }
     }
 }
@@ -132,7 +137,7 @@ fn TodoHeader(mut todos: Signal<HashMap<u32, TodoItem>>) -> Element {
                 value: "{draft}",
                 autofocus: "true",
                 oninput: move |evt| draft.set(evt.value()),
-                onkeydown,
+                onkeydown
             }
         }
     }
@@ -165,7 +170,7 @@ fn TodoEntry(mut todos: Signal<HashMap<u32, TodoItem>>, id: u32) -> Element {
                     r#type: "checkbox",
                     id: "cbg-{id}",
                     checked: "{checked}",
-                    oninput: move |evt| todos.write().get_mut(&id).unwrap().checked = evt.checked(),
+                    oninput: move |evt| todos.write().get_mut(&id).unwrap().checked = evt.checked()
                 }
                 label {
                     r#for: "cbg-{id}",
@@ -175,7 +180,9 @@ fn TodoEntry(mut todos: Signal<HashMap<u32, TodoItem>>, id: u32) -> Element {
                 }
                 button {
                     class: "destroy",
-                    onclick: move |_| { todos.write().remove(&id); },
+                    onclick: move |_| {
+                        todos.write().remove(&id);
+                    },
                     prevent_default: "onclick"
                 }
             }
@@ -211,41 +218,41 @@ fn ListFooter(
     let show_clear_completed = use_memo(move || todos.read().values().any(|todo| todo.checked));
 
     rsx! {
-        footer { class: "footer",
-            span { class: "todo-count",
-                strong { "{active_todo_count} " }
-                span {
-                    match active_todo_count() {
-                        1 => "item",
-                        _ => "items",
+            footer { class: "footer",
+                span { class: "todo-count",
+                    strong { "{active_todo_count} " }
+                    span {
+                        match active_todo_count() {
+                            1 => "item",
+                            _ => "items",
+                        },
+                        " left"
                     }
-                    " left"
                 }
-            }
-            ul { class: "filters",
-                for (state , state_text , url) in [
-                    (FilterState::All, "All", "#/"),
-                    (FilterState::Active, "Active", "#/active"),
-                    (FilterState::Completed, "Completed", "#/completed"),
-                ] {
-                    li {
-                        a {
-                            href: url,
-                            class: if filter() == state { "selected" },
-                            onclick: move |_| filter.set(state),
-                            prevent_default: "onclick",
-                            {state_text}
+                ul { class: "filters",
+                    for (state , state_text , url) in [
+        (FilterState::All, "All", "#/"),
+        (FilterState::Active, "Active", "#/active"),
+        (FilterState::Completed, "Completed", "#/completed"),
+    ] {
+                        li {
+                            a {
+                                href: url,
+                                class: if filter() == state { "selected" },
+                                onclick: move |_| filter.set(state),
+                                prevent_default: "onclick",
+                                {state_text}
+                            }
                         }
                     }
                 }
-            }
-            if show_clear_completed() {
-                button {
-                    class: "clear-completed",
-                    onclick: move |_| todos.write().retain(|_, todo| !todo.checked),
-                    "Clear completed"
+                if show_clear_completed() {
+                    button {
+                        class: "clear-completed",
+                        onclick: move |_| todos.write().retain(|_, todo| !todo.checked),
+                        "Clear completed"
+                    }
                 }
             }
         }
-    }
 }

+ 1 - 1
packages/core/src/global_context.rs

@@ -145,7 +145,7 @@ pub fn remove_future(id: Task) {
 ///
 /// pub fn use_custom_state() -> CustomState {
 ///     use_hook(|| CustomState {
-///         inner: Signal::new(InnerCustomState)
+///         inner: Signal::new(InnerCustomState(0))
 ///     })
 /// }
 /// ```

+ 1 - 1
packages/core/src/scope_context.rs

@@ -310,7 +310,7 @@ impl Scope {
     ///
     /// pub fn use_custom_state() -> CustomState {
     ///     use_hook(|| CustomState {
-    ///         inner: Signal::new(InnerCustomState)
+    ///         inner: Signal::new(InnerCustomState(0))
     ///     })
     /// }
     /// ```

+ 4 - 6
packages/core/src/virtual_dom.rs

@@ -138,7 +138,7 @@ use tracing::instrument;
 ///
 /// let dom = VirtualDom::new(app);
 ///
-/// real_dom.apply(dom.rebuild());
+/// dom.rebuild(real_dom.apply());
 ///
 /// loop {
 ///     select! {
@@ -258,7 +258,7 @@ impl VirtualDom {
     ///
     /// ```rust, ignore
     /// let mut dom = VirtualDom::new_with_props(Example, SomeProps { name: "jane" });
-    /// let mutations = dom.rebuild();
+    /// dom.rebuild_in_place();
     /// ```
     pub fn new_with_props<P: Clone + 'static, M: 'static>(
         root: impl ComponentFunction<P, M>,
@@ -302,7 +302,7 @@ impl VirtualDom {
     ///
     /// ```rust, ignore
     /// let mut dom = VirtualDom::new_from_root(VComponent::new(Example, SomeProps { name: "jane" }, "Example"));
-    /// let mutations = dom.rebuild();
+    /// dom.rebuild(to_writer);
     /// ```
     #[instrument(skip(root), level = "trace", name = "VirtualDom::new")]
     pub(crate) fn new_with_component(root: impl AnyProps + 'static) -> Self {
@@ -611,9 +611,7 @@ impl VirtualDom {
     /// static app: Component = |cx|  rsx!{ "hello world" };
     ///
     /// let mut dom = VirtualDom::new();
-    /// let edits = dom.rebuild();
-    ///
-    /// apply_edits(edits);
+    /// dom.rebuild(to_writer);
     /// ```
     #[instrument(skip(self, to), level = "trace", name = "VirtualDom::rebuild")]
     pub fn rebuild(&mut self, to: &mut impl WriteMutations) {

+ 0 - 1
packages/core/tests/miri_full_app.rs

@@ -1,4 +1,3 @@
-use crate::dioxus_elements::SerializedMouseData;
 use dioxus::prelude::*;
 use dioxus_core::ElementId;
 use dioxus_elements::SerializedHtmlEventConverter;

+ 4 - 2
packages/core/tests/task.rs

@@ -66,7 +66,7 @@ async fn spawn_forever_persists() {
     #[component]
     fn Child() -> Element {
         spawn_forever(async move {
-            loop {
+            for _ in 0..10 {
                 POLL_COUNT.fetch_add(1, Ordering::Relaxed);
                 tokio::time::sleep(Duration::from_millis(50)).await;
             }
@@ -82,7 +82,9 @@ async fn spawn_forever_persists() {
 
     tokio::select! {
         _ = dom.wait_for_work() => {}
-        _ = tokio::time::sleep(Duration::from_millis(500)) => {}
+        // We intentionally wait a bit longer than 50ms*10 to make sure the test has time to finish
+        // Without the extra time, the test can fail on windows
+        _ = tokio::time::sleep(Duration::from_millis(1000)) => {}
     };
 
     // By the time the tasks are finished, we should've accumulated ticks from two tasks

+ 29 - 13
packages/desktop/headless_tests/events.rs

@@ -2,7 +2,6 @@ use std::collections::HashMap;
 
 use dioxus::html::geometry::euclid::Vector3D;
 use dioxus::prelude::*;
-use dioxus_core::prelude::consume_context;
 use dioxus_desktop::DesktopContext;
 
 #[path = "./utils.rs"]
@@ -179,7 +178,10 @@ fn test_mouse_dblclick_div() -> Element {
                 println!("{:?}", event.data);
                 assert!(event.data.modifiers().is_empty());
                 assert!(
-                    event.data.held_buttons().contains(dioxus_html::input_data::MouseButton::Primary),
+                    event
+                        .data
+                        .held_buttons()
+                        .contains(dioxus_html::input_data::MouseButton::Primary),
                 );
                 assert!(
                     event
@@ -282,7 +284,8 @@ fn test_mouse_scroll_div() -> Element {
             onwheel: move |event| {
                 println!("{:?}", event.data);
                 let dioxus_html::geometry::WheelDelta::Pixels(delta) = event.data.delta() else {
-                panic!("Expected delta to be in pixels") };
+                    panic!("Expected delta to be in pixels")
+                };
                 assert_eq!(delta, Vector3D::new(1.0, 2.0, 3.0));
                 RECEIVED_EVENTS.with_mut(|x| *x += 1);
             }
@@ -476,11 +479,16 @@ fn test_form_input() -> Element {
                     r#type: "text",
                     name: "username",
                     id: "form-username",
-                    oninput: set_username,
+                    oninput: set_username
                 }
                 input { r#type: "text", name: "full-name", value: "lorem" }
                 input { r#type: "password", name: "password", value: "ipsum" }
-                input { r#type: "radio", name: "color", value: "red", checked: true }
+                input {
+                    r#type: "radio",
+                    name: "color",
+                    value: "red",
+                    checked: true
+                }
                 input { r#type: "radio", name: "color", value: "blue" }
                 button { r#type: "submit", value: "Submit", "Submit the form" }
             }
@@ -511,13 +519,21 @@ fn test_form_submit() -> Element {
     rsx! {
         div {
             h1 { "Form" }
-            form {
-                id: "form-submitter",
-                onsubmit: set_values,
-                input { r#type: "text", name: "username", id: "username", value: "goodbye" }
+            form { id: "form-submitter", onsubmit: set_values,
+                input {
+                    r#type: "text",
+                    name: "username",
+                    id: "username",
+                    value: "goodbye"
+                }
                 input { r#type: "text", name: "full-name", value: "lorem" }
                 input { r#type: "password", name: "password", value: "ipsum" }
-                input { r#type: "radio", name: "color", value: "red", checked: true }
+                input {
+                    r#type: "radio",
+                    name: "color",
+                    value: "red",
+                    checked: true
+                }
                 input { r#type: "radio", name: "color", value: "blue" }
                 button { r#type: "submit", value: "Submit", "Submit the form" }
             }
@@ -547,9 +563,9 @@ fn test_select_multiple_options() -> Element {
                 assert_eq!(values, vec!["usa", "canada"]);
                 RECEIVED_EVENTS.with_mut(|x| *x += 1);
             },
-            option { id: "usa", value: "usa",  "USA" }
-            option { id: "canada", value: "canada",  "Canada" }
-            option { id: "mexico", value: "mexico", selected: true,  "Mexico" }
+            option { id: "usa", value: "usa", "USA" }
+            option { id: "canada", value: "canada", "Canada" }
+            option { id: "mexico", value: "mexico", selected: true, "Mexico" }
         }
     }
 }

+ 4 - 14
packages/desktop/headless_tests/rendering.rs

@@ -1,5 +1,4 @@
 use dioxus::prelude::*;
-use dioxus_core::Element;
 use dioxus_desktop::DesktopContext;
 
 #[path = "./utils.rs"]
@@ -53,26 +52,17 @@ fn check_html_renders() -> Element {
     }
 
     let dyn_value = 0;
-    let dyn_element = rsx! {
-        div {
-            dangerous_inner_html: "<p>hello world</p>",
-        }
-    };
+    let dyn_element = rsx! { div { dangerous_inner_html: "<p>hello world</p>" } };
 
     rsx! {
-        div {
-            id: "main_div",
+        div { id: "main_div",
             div {
                 width: "100px",
                 height: "100px",
                 color: "rgb({dyn_value}, {dyn_value}, {dyn_value})",
                 id: 5,
-                input {
-                    "type": "checkbox",
-                },
-                h1 {
-                    "text"
-                }
+                input { "type": "checkbox" }
+                h1 { "text" }
                 {dyn_element}
             }
         }

+ 1 - 1
packages/desktop/headless_tests/utils.rs

@@ -18,7 +18,7 @@ pub fn check_app_exits(app: fn() -> Element) {
     });
 
     LaunchBuilder::desktop()
-        .with_cfg(Config::new().with_window(WindowBuilder::new().with_visible(true)))
+        .with_cfg(Config::new().with_window(WindowBuilder::new().with_visible(false)))
         .launch(app);
 
     // Stop deadman's switch

+ 3 - 0
packages/dioxus-lib/Cargo.toml

@@ -19,6 +19,9 @@ dioxus-hooks = { workspace = true, optional = true }
 dioxus-rsx = { workspace = true, optional = true }
 dioxus-signals = { workspace = true, optional = true }
 
+[dev-dependencies]
+dioxus = { workspace = true }
+
 [features]
 default = ["macro", "html", "signals", "hooks"]
 signals = ["dioxus-signals"]

+ 3 - 3
packages/dioxus-lib/README.md

@@ -1,5 +1,5 @@
 <div>
-  <h1>🌗🚀 Dioxus</h1>
+  <h1>🌗🚀 Dioxus (lib)</h1>
   <p>
     <strong>A concurrent, functional, virtual DOM for Rust</strong>
   </p>
@@ -38,9 +38,9 @@ Remember: Dioxus is a library for declaring interactive user interfaces—it is
 
 All Dioxus apps are built by composing functions that return an `Element`.
 
-To launch an app, we use the `launch` method and use features in ``Cargo.toml`` to specify which renderer we want to use. In the launch function, we pass the app's root `Component`.
+To launch an app, we use the `launch` method and use features in `Cargo.toml` to specify which renderer we want to use. In the launch function, we pass the app's root `Component`.
 
-```rust
+```rust, no_run
 use dioxus::prelude::*;
 
 fn main() {

+ 2 - 2
packages/dioxus/README.md

@@ -36,9 +36,9 @@ Remember: Dioxus is a library for declaring interactive user interfaces—it is
 
 All Dioxus apps are built by composing functions that return an `Element`.
 
-To launch an app, we use the `launch` method and use features in ``Cargo.toml`` to specify which renderer we want to use. In the launch function, we pass the app's root `Component`.
+To launch an app, we use the `launch` method and use features in `Cargo.toml` to specify which renderer we want to use. In the launch function, we pass the app's root `Component`.
 
-```rust
+```rust, no_run
 use dioxus::prelude::*;
 
 fn main() {

+ 3 - 0
packages/fullstack/Cargo.toml

@@ -66,6 +66,9 @@ tokio = { workspace = true, features = ["rt", "sync"], optional = true }
 dioxus-hot-reload = { workspace = true }
 tokio = { workspace = true, features = ["rt", "sync", "rt-multi-thread"], optional = true }
 
+[dev-dependencies]
+dioxus = { workspace = true, features = ["fullstack"] }
+
 [features]
 default = ["hot-reload"]
 hot-reload = ["serde_json"]

+ 2 - 2
packages/fullstack/README.md

@@ -32,7 +32,7 @@ Fullstack utilities for the [`Dioxus`](https://dioxuslabs.com) framework.
 
 Full stack Dioxus in under 30 lines of code
 
-```rust
+```rust, no_run
 #![allow(non_snake_case)]
 use dioxus::prelude::*;
 
@@ -42,7 +42,7 @@ fn main() {
 
 #[component]
 fn App() -> Element {
-    let meaning = use_signal(|| None);
+    let mut meaning = use_signal(|| None);
 
     rsx! {
         h1 { "Meaning of life: {meaning:?}" }

+ 2 - 2
packages/fullstack/src/hooks/server_cached.rs

@@ -12,9 +12,9 @@ use serde::{de::DeserializeOwned, Serialize};
 /// use dioxus_fullstack::prelude::*;
 ///
 /// fn app() -> Element {
-///    let state1 = server_cached(|| from_server(|| {
+///    let state1 = server_cached(|| {
 ///       1234
-///    }));
+///    });
 ///
 ///    None
 /// }

+ 1 - 1
packages/hooks/src/use_effect.rs

@@ -34,7 +34,7 @@ use crate::use_callback;
 /// #[component]
 /// fn Comp(count: u32) -> Element {
 ///     // Because the memo subscribes to `count` by adding it as a dependency, the memo will rerun every time `count` changes.
-///     use_effect(use_reactive((&count, |(count,)| println!("Manually manipulate the dom") )));
+///     use_effect(use_reactive((&count,), |(count,)| println!("Manually manipulate the dom") ));
 ///
 ///     todo!()
 /// }

+ 1 - 1
packages/hooks/src/use_memo.rs

@@ -32,7 +32,7 @@ use dioxus_signals::{Memo, Signal};
 /// #[component]
 /// fn Comp(count: u32) -> Element {
 ///     // Because the memo subscribes to `count` by adding it as a dependency, the memo will rerun every time `count` changes.
-///     let new_count = use_memo(use_reactive((&count, |(count,)| count + 1)));
+///     let new_count = use_memo(use_reactive((&count,), |(count,)| count + 1));
 ///
 ///     todo!()
 /// }

+ 2 - 2
packages/hooks/src/use_reactive.rs

@@ -74,7 +74,7 @@ impl_dep!(A = a1 a2, B = b1 b2, C = c1 c2, D = d1 d2, E = e1 e2, F = f1 f2, G =
 ///
 /// # Example
 ///
-/// ```rust
+/// ```rust, no_run
 /// use dioxus::prelude::*;
 ///
 /// let data = 5;
@@ -104,7 +104,7 @@ pub fn use_reactive<O, D: Dependency>(
 ///
 /// # Example
 ///
-/// ```rust
+/// ```rust, no_run
 /// use dioxus::prelude::*;
 ///
 /// let data = 5;

+ 1 - 5
packages/hooks/src/use_resource.rs

@@ -2,10 +2,6 @@
 
 use crate::{use_callback, use_signal, UseCallback};
 use dioxus_core::prelude::*;
-use dioxus_core::{
-    prelude::{spawn, use_hook},
-    Task,
-};
 use dioxus_signals::*;
 use futures_util::{future, pin_mut, FutureExt, StreamExt};
 use std::ops::Deref;
@@ -66,7 +62,7 @@ use std::{cell::Cell, future::Future, rc::Rc};
 /// #[component]
 /// fn Comp(count: u32) -> Element {
 ///     // Because the memo subscribes to `count` by adding it as a dependency, the memo will rerun every time `count` changes.
-///     let new_count = use_resource(use_reactive((&count, |(count,)| async move {count + 1} )));
+///     let new_count = use_resource(use_reactive((&count,), |(count,)| async move {count + 1} ));
 ///
 ///     todo!()
 /// }

+ 4 - 4
packages/html/README.md

@@ -25,7 +25,7 @@ The Dioxus `rsx!` and `html!` macros can accept any compile-time correct namespa
 
 However, this abstraction enables you to add any namespace of elements, provided they're in scope when rsx! is called. For an example, a UI that is designed for Augmented Reality might use different primitives than HTML:
 
-```rust
+```rust, ignore
 use ar_namespace::*;
 
 rsx! {
@@ -46,7 +46,7 @@ This is currently a not-very-explored part of Dioxus. However, the namespacing s
 
 Elements for dioxus must implement the (simple) DioxusElement trait to be used in the rsx! macro.
 
-```rust
+```rust, ignore
 struct div;
 impl DioxusElement for div {
     const TAG_NAME: &'static str = "div";
@@ -60,7 +60,7 @@ Attributes would then be implemented as constants on these unit structs.
 
 The HTML namespace is defined mostly with macros. However, the expanded form would look something like this:
 
-```rust
+```rust, ignore
 struct base;
 impl DioxusElement for base {
     const TAG_NAME: &'static str = "base";
@@ -78,7 +78,7 @@ Because attributes are defined as methods on the unit struct, they guard the att
 
 Whenever the rsx! macro is called, it relies on a module `dioxus_elements` to be in scope. When you enable the `html` feature in dioxus, this module gets imported in the prelude. However, you can extend this with your own set of custom elements by making your own `dioxus_elements` module and re-exporting the html namespace.
 
-```rust
+```rust, ignore
 mod dioxus_elements {
     use dioxus::prelude::dioxus_elements::*;
     struct my_element;

+ 3 - 1
packages/liveview/src/lib.rs

@@ -106,7 +106,9 @@ fn handle_edits_code() -> String {
 /// If you enter a relative path, the web client automatically prefixes the host address in
 /// `window.location` when creating a web socket to LiveView.
 ///
-/// ```
+/// ```rust
+/// use dioxus_liveview::interpreter_glue;
+///
 /// // Creates websocket connection to same host as current page
 /// interpreter_glue("/api/liveview");
 ///

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

@@ -20,6 +20,9 @@ quote = { workspace = true }
 proc-macro2 = { workspace = true }
 slab = { workspace = true }
 
+[dev-dependencies]
+dioxus = { workspace = true, features = ["router"] }
+
 [features]
 default = []
 web = []

+ 56 - 14
packages/router-macro/src/lib.rs

@@ -42,7 +42,9 @@ mod segment;
 /// 2. By the order they are defined in the enum
 ///
 /// All features:
-/// ```rust, skip
+/// ```rust
+/// use dioxus::prelude::*;
+///
 /// #[rustfmt::skip]
 /// #[derive(Clone, Debug, PartialEq, Routable)]
 /// enum Route {
@@ -75,9 +77,17 @@ mod segment;
 ///     #[redirect("/:id/user", |id: usize| Route::Route3 { dynamic: id.to_string()})]
 ///     #[route("/:dynamic")]
 ///     Route3 { dynamic: String },
-///     #[child]
-///     NestedRoute(NestedRoute),
 /// }
+/// # #[component]
+/// # fn Route1(user_id: usize, dynamic: usize, query: String) -> Element { None }
+/// # #[component]
+/// # fn Route2(user_id: usize) -> Element { None }
+/// # #[component]
+/// # fn Route3(dynamic: String) -> Element { None }
+/// # #[component]
+/// # fn UserFrame(user_id: usize) -> Element { None }
+/// # #[component]
+/// # fn IndexComponent() -> Element { None }
 /// ```
 ///
 /// # `#[route("path", component)]`
@@ -89,7 +99,9 @@ mod segment;
 /// Routes are the most basic attribute. They allow you to define a route and the component to render when the route is matched. The component must take all dynamic parameters of the route and all parent nests.
 /// The next variant will be tied to the component. If you link to that variant, the component will be rendered.
 ///
-/// ```rust, skip
+/// ```rust
+/// use dioxus::prelude::*;
+///
 /// #[derive(Clone, Debug, PartialEq, Routable)]
 /// enum Route {
 ///     // Define routes that renders the IndexComponent
@@ -97,6 +109,8 @@ mod segment;
 ///     #[route("/", Index)]
 ///     Index {},
 /// }
+/// # #[component]
+/// # fn Index() -> Element { None }
 /// ```
 ///
 /// # `#[redirect("path", function)]`
@@ -105,14 +119,18 @@ mod segment;
 /// - `path`: The path to the enum variant (relative to the parent nest)
 /// - `function`: A function that takes the parameters from the path and returns a new route
 ///
-/// ```rust, skip
+/// ```rust
+/// use dioxus::prelude::*;
+///
 /// #[derive(Clone, Debug, PartialEq, Routable)]
 /// enum Route {
 ///     // Redirects the /:id route to the Index route
-///     #[redirect("/:id", |_: usize| Route::Index {})]
+///     #[redirect("/:id", |id: usize| Route::Index {})]
 ///     #[route("/", Index)]
 ///     Index {},
 /// }
+/// # #[component]
+/// # fn Index() -> Element { None }
 /// ```
 ///
 /// Redirects allow you to redirect a route to another route. The function must take all dynamic parameters of the route and all parent nests.
@@ -124,29 +142,35 @@ mod segment;
 ///
 /// Nests effect all nests, routes and redirects defined until the next `#[end_nest]` attribute. All children of nests are relative to the nest route and must include all dynamic parameters of the nest.
 ///
-/// ```rust, skip
+/// ```rust
+/// use dioxus::prelude::*;
+///
 /// #[derive(Clone, Debug, PartialEq, Routable)]
 /// enum Route {
 ///     // Nests all child routes in the /blog route
 ///     #[nest("/blog")]
 ///         // This is at /blog/:id
-///         #[redirect("/:id", |_: usize| Route::Index {})]
+///         #[redirect("/:id", |id: usize| Route::Index {})]
 ///         // This is at /blog
 ///         #[route("/", Index)]
 ///         Index {},
 /// }
+/// # #[component]
+/// # fn Index() -> Element { None }
 /// ```
 ///
 /// # `#[end_nest]`
 ///
 /// The `#[end_nest]` attribute is used to end a nest. It takes no parameters.
 ///
-/// ```rust, skip
+/// ```rust
+/// use dioxus::prelude::*;
+///
 /// #[derive(Clone, Debug, PartialEq, Routable)]
 /// enum Route {
 ///     #[nest("/blog")]
 ///         // This is at /blog/:id
-///         #[redirect("/:id", |_: usize| Route::Index {})]
+///         #[redirect("/:id", |id: usize| Route::Index {})]
 ///         // This is at /blog
 ///         #[route("/", Index)]
 ///         Index {},
@@ -156,6 +180,10 @@ mod segment;
 ///     #[route("/")]
 ///     Home {},
 /// }
+/// # #[component]
+/// # fn Index() -> Element { None }
+/// # #[component]
+/// # fn Home() -> Element { None }
 /// ```
 ///
 /// # `#[layout(component)]`
@@ -165,26 +193,34 @@ mod segment;
 ///
 /// The layout component allows you to wrap all children of the layout in a component. The child routes are rendered in the Outlet of the layout component. The layout component must take all dynamic parameters of the nests it is nested in.
 ///
-/// ```rust, skip
+/// ```rust
+/// use dioxus::prelude::*;
+///
 /// #[derive(Clone, Debug, PartialEq, Routable)]
 /// enum Route {
 ///     #[layout(BlogFrame)]
-///         #[redirect("/:id", |_: usize| Route::Index {})]
+///         #[redirect("/:id", |id: usize| Route::Index {})]
 ///         // Index will be rendered in the Outlet of the BlogFrame component
 ///         #[route("/", Index)]
 ///         Index {},
 /// }
+/// # #[component]
+/// # fn Index() -> Element { None }
+/// # #[component]
+/// # fn BlogFrame() -> Element { None }
 /// ```
 ///
 /// # `#[end_layout]`
 ///
 /// The `#[end_layout]` attribute is used to end a layout. It takes no parameters.
 ///
-/// ```rust, skip
+/// ```rust
+/// use dioxus::prelude::*;
+///
 /// #[derive(Clone, Debug, PartialEq, Routable)]
 /// enum Route {
 ///     #[layout(BlogFrame)]
-///         #[redirect("/:id", |_: usize| Route::Index {})]
+///         #[redirect("/:id", |id: usize| Route::Index {})]
 ///         // Index will be rendered in the Outlet of the BlogFrame component
 ///         #[route("/", Index)]
 ///         Index {},
@@ -194,6 +230,12 @@ mod segment;
 ///     #[route("/")]
 ///     Home {},
 /// }
+/// # #[component]
+/// # fn Index() -> Element { None }
+/// # #[component]
+/// # fn BlogFrame() -> Element { None }
+/// # #[component]
+/// # fn Home() -> Element { None }
 /// ```
 #[proc_macro_derive(
     Routable,

+ 13 - 3
packages/router/src/components/history_buttons.rs

@@ -73,7 +73,12 @@ pub fn GoBackButton(props: HistoryButtonProps) -> Element {
     let disabled = !router.can_go_back();
 
     rsx! {
-        button { disabled: "{disabled}", prevent_default: "onclick", onclick: move |_| router.go_back(), {children} }
+        button {
+            disabled: "{disabled}",
+            prevent_default: "onclick",
+            onclick: move |_| router.go_back(),
+            {children}
+        }
     }
 }
 
@@ -114,7 +119,7 @@ pub fn GoBackButton(props: HistoryButtonProps) -> Element {
 /// }
 /// #
 /// # let mut vdom = VirtualDom::new(App);
-/// # let _ = vdom.rebuild();
+/// # vdom.rebuild_in_place();
 /// # assert_eq!(
 /// #     dioxus_ssr::render(&vdom),
 /// #     r#"<button disabled="true" dioxus-prevent-default="onclick">go forward</button>"#
@@ -139,6 +144,11 @@ pub fn GoForwardButton(props: HistoryButtonProps) -> Element {
     let disabled = !router.can_go_forward();
 
     rsx! {
-        button { disabled: "{disabled}", prevent_default: "onclick", onclick: move |_| router.go_forward(), {children} }
+        button {
+            disabled: "{disabled}",
+            prevent_default: "onclick",
+            onclick: move |_| router.go_forward(),
+            {children}
+        }
     }
 }

+ 10 - 12
packages/router/src/components/link.rs

@@ -178,26 +178,24 @@ impl Debug for LinkProps {
 /// #[component]
 /// fn Index() -> Element {
 ///     rsx! {
-///         rsx! {
-///             Link {
-///                 active_class: "active",
-///                 class: "link_class",
-///                 id: "link_id",
-///                 new_tab: true,
-///                 rel: "link_rel",
-///                 to: Route::Index {},
+///         Link {
+///             active_class: "active",
+///             class: "link_class",
+///             id: "link_id",
+///             new_tab: true,
+///             rel: "link_rel",
+///             to: Route::Index {},
 ///
-///                 "A fully configured link"
-///             }
+///             "A fully configured link"
 ///         }
 ///     }
 /// }
 /// #
 /// # let mut vdom = VirtualDom::new(App);
-/// # let _ = vdom.rebuild();
+/// # vdom.rebuild_in_place();
 /// # assert_eq!(
 /// #     dioxus_ssr::render(&vdom),
-/// #     r#"<a href="/" dioxus-prevent-default="" class="link_class active" id="link_id" rel="link_rel" target="_blank">A fully configured link</a>"#
+/// #     r#"<a href="/" dioxus-prevent-default="" class="link_class active" rel="link_rel" target="_blank" id="link_id">A fully configured link</a>"#
 /// # );
 /// ```
 #[allow(non_snake_case)]

+ 1 - 1
packages/router/src/components/outlet.rs

@@ -65,7 +65,7 @@ use dioxus_lib::prelude::*;
 /// # }
 /// #
 /// # let mut vdom = VirtualDom::new(App);
-/// # let _ = vdom.rebuild();
+/// # vdom.rebuild_in_place();
 /// # assert_eq!(dioxus_ssr::render(&vdom), "<h1>App</h1><p>Child</p>");
 /// ```
 pub fn Outlet<R: Routable + Clone>() -> Element {

+ 1 - 1
packages/router/src/hooks/use_navigator.rs

@@ -46,7 +46,7 @@ use crate::prelude::{Navigator, RouterContext};
 /// }
 ///
 /// # let mut vdom = VirtualDom::new(App);
-/// # let _ = vdom.rebuild();
+/// # vdom.rebuild_in_place();
 /// ```
 #[must_use]
 pub fn use_navigator() -> Navigator {

+ 1 - 1
packages/router/src/hooks/use_route.rs

@@ -37,7 +37,7 @@ use crate::utils::use_router_internal::use_router_internal;
 /// }
 /// #
 /// # let mut vdom = VirtualDom::new(App);
-/// # let _ = vdom.rebuild();
+/// # vdom.rebuild_in_place();
 /// # assert_eq!(dioxus_ssr::render(&vdom), "<h1>App</h1><h2>Current Path</h2><p>/</p>")
 /// ```
 #[must_use]

+ 3 - 3
packages/ssr/README.md

@@ -21,7 +21,7 @@ Dioxus SSR provides utilities to render Dioxus components to valid HTML. Once re
 let app: Component = |cx| rsx!(div {"hello world!"});
 
 let mut vdom = VirtualDom::new(app);
-let _ = vdom.rebuild();
+vdom.rebuild_in_place();
 
 let text = dioxus_ssr::render(&vdom);
 assert_eq!(text, "<div>hello world!</div>")
@@ -45,7 +45,7 @@ let content = dioxus_ssr::render_element(rsx!{
 
 ```rust, ignore
 let mut vdom = VirtualDom::new(app);
-let _ = vdom.rebuild();
+vdom.rebuild_in_place();
 
 let content = dioxus_ssr::render(&vdom);
 ```
@@ -63,7 +63,7 @@ To enable pre-rendering, simply set the pre-rendering flag to true.
 ```rust, ignore
 let mut vdom = VirtualDom::new(App);
 
-let _ = vdom.rebuild();
+vdom.rebuild_in_place();
 
 let mut renderer = dioxus_ssr::Renderer::new();
 renderer.pre_render = true;