Pārlūkot izejas kodu

Merge branch 'master' into fix-event-bubbling

Evan Almloff 1 gadu atpakaļ
vecāks
revīzija
b0733958f2

+ 22 - 24
.github/workflows/main.yml

@@ -85,52 +85,56 @@ jobs:
 
   matrix_test:
     runs-on: ${{ matrix.platform.os }}
+    env:
+      RUST_CARGO_COMMAND: ${{ matrix.platform.cross == true && 'cross' || 'cargo' }}
     strategy:
       matrix:
         platform:
           - {
               target: x86_64-pc-windows-msvc,
               os: windows-latest,
-              toolchain: '1.70.0',
+              toolchain: "1.70.0",
               cross: false,
-              command: 'test',
-              args: '--all --tests'
+              command: "test",
+              args: "--all --tests",
             }
           - {
               target: x86_64-apple-darwin,
               os: macos-latest,
-              toolchain: '1.70.0',
+              toolchain: "1.70.0",
               cross: false,
-              command: 'test',
-              args: '--all --tests'
+              command: "test",
+              args: "--all --tests",
             }
           - {
               target: aarch64-apple-ios,
               os: macos-latest,
-              toolchain: '1.70.0',
+              toolchain: "1.70.0",
               cross: false,
-              command: 'build',
-              args: '--package dioxus-mobile'
+              command: "build",
+              args: "--package dioxus-mobile",
             }
           - {
               target: aarch64-linux-android,
               os: ubuntu-latest,
-              toolchain: '1.70.0',
+              toolchain: "1.70.0",
               cross: true,
-              command: 'build',
-              args: '--package dioxus-mobile'
+              command: "build",
+              args: "--package dioxus-mobile",
             }
 
     steps:
       - uses: actions/checkout@v3
 
       - name: install stable
-        uses: actions-rs/toolchain@v1
+        uses: dtolnay/rust-toolchain@master
         with:
           toolchain: ${{ matrix.platform.toolchain }}
-          target: ${{ matrix.platform.target }}
-          override: true
-          default: true
+          targets: ${{ matrix.platform.target }}
+
+      - name: Install cross
+        if: ${{ matrix.platform.cross == true }}
+        uses: taiki-e/install-action@cross
 
       - uses: Swatinem/rust-cache@v2
         with:
@@ -138,13 +142,8 @@ jobs:
           save-if: ${{ matrix.features.key == 'all' }}
 
       - name: test
-        uses: actions-rs/cargo@v1
-        with:
-          use-cross: ${{ matrix.platform.cross }}
-          command: ${{ matrix.platform.command }}
-          args: --target ${{ matrix.platform.target }} ${{ matrix.platform.args }}
-
-
+        run: |
+          ${{ env.RUST_CARGO_COMMAND }} ${{ matrix.platform.command }} ${{ matrix.platform.args }} --target ${{ matrix.platform.target }}
 
   # Coverage is disabled until we can fix it
   # coverage:
@@ -166,4 +165,3 @@ jobs:
   #       uses: codecov/codecov-action@v2
   #       with:
   #         fail_ci_if_error: false
-

+ 34 - 37
.github/workflows/playwright.yml

@@ -1,9 +1,9 @@
 name: Playwright Tests
 on:
   push:
-    branches: [ main, master ]
+    branches: [main, master]
   pull_request:
-    branches: [ main, master ]
+    branches: [main, master]
 defaults:
   run:
     working-directory: ./playwright-tests
@@ -16,39 +16,36 @@ jobs:
   test:
     if: github.event.pull_request.draft == false
     timeout-minutes: 60
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-latest
     steps:
-    # Do our best to cache the toolchain and node install steps
-    - uses: actions/checkout@v3
-    - uses: actions/setup-node@v3
-      with:
-        node-version: 16
-    - name: Install Rust
-      uses: actions-rs/toolchain@v1
-      with:
-        profile: minimal
-        toolchain: stable
-        override: true
-    - uses: Swatinem/rust-cache@v2
-    - name: Install WASM toolchain
-      run: rustup target add wasm32-unknown-unknown
-    - name: Install dependencies
-      run: npm ci
-    - name: Install Playwright
-      run: npm install -D @playwright/test
-    - name: Install Playwright Browsers
-      run: npx playwright install --with-deps
-    #  Cache the CLI by using cargo run internally
-    # - name: Install Dioxus CLI
-    #   uses: actions-rs/cargo@v1
-    #   with:
-    #     command: install
-    #     args: --path packages/cli
-    - name: Run Playwright tests
-      run: npx playwright test
-    - uses: actions/upload-artifact@v3
-      if: always()
-      with:
-        name: playwright-report
-        path: playwright-report/
-        retention-days: 30
+      # Do our best to cache the toolchain and node install steps
+      - uses: actions/checkout@v3
+      - uses: actions/setup-node@v3
+        with:
+          node-version: 16
+      - name: Install Rust
+        uses: dtolnay/rust-toolchain@master
+        with:
+          toolchain: stable
+          targets: x86_64-unknown-linux-gnu,wasm32-unknown-unknown
+      - uses: Swatinem/rust-cache@v2
+      - name: Install dependencies
+        run: npm ci
+      - name: Install Playwright
+        run: npm install -D @playwright/test
+      - name: Install Playwright Browsers
+        run: npx playwright install --with-deps
+      #  Cache the CLI by using cargo run internally
+      # - name: Install Dioxus CLI
+      #   uses: actions-rs/cargo@v1
+      #   with:
+      #     command: install
+      #     args: --path packages/cli
+      - name: Run Playwright tests
+        run: npx playwright test
+      - uses: actions/upload-artifact@v3
+        if: always()
+        with:
+          name: playwright-report
+          path: playwright-report/
+          retention-days: 30

+ 2 - 2
Cargo.toml

@@ -50,12 +50,12 @@ members = [
 exclude = ["examples/mobile_demo"]
 
 [workspace.package]
-version = "0.4.1"
+version = "0.4.2"
 
 # dependencies that are shared across packages
 [workspace.dependencies]
 dioxus = { path = "packages/dioxus", version = "0.4.0" }
-dioxus-core = { path = "packages/core", version = "0.4.1" }
+dioxus-core = { path = "packages/core", version = "0.4.2" }
 dioxus-core-macro = { path = "packages/core-macro", version = "0.4.0"  }
 dioxus-router = { path = "packages/router", version = "0.4.1"  }
 dioxus-router-macro = { path = "packages/router-macro", version = "0.4.1" }

+ 1 - 1
examples/mobile_demo/src/lib.rs

@@ -72,7 +72,7 @@ fn app(cx: Scope) -> Element {
                     onclick: move|_| {
                         println!("Clicked!");
                         items.push(items.len());
-                        cx.needs_update_any(ScopeId(0));
+                        cx.needs_update_any(ScopeId::ROOT);
                         println!("Requested update");
                     },
                     "Add item"

+ 9 - 25
packages/cli/.github/workflows/main.yml

@@ -8,47 +8,31 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v2
-      - uses: actions-rs/toolchain@v1
-        with:
-          profile: minimal
-          toolchain: stable
-          override: true
+      - name: Install Rust
+        uses: dtolnay/rust-toolchain@stable
       - uses: Swatinem/rust-cache@v1
-      - uses: actions-rs/cargo@v1
-        with:
-          command: check
+      - run: cargo check
 
   test:
     name: Test Suite
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v2
-      - uses: actions-rs/toolchain@v1
-        with:
-          profile: minimal
-          toolchain: stable
-          override: true
+      - name: Install Rust
+        uses: dtolnay/rust-toolchain@stable
       - uses: Swatinem/rust-cache@v1
-      - uses: actions-rs/cargo@v1
-        with:
-          command: test
+      - run: cargo test
 
   fmt:
     name: Rustfmt
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v2
-      - uses: actions-rs/toolchain@v1
-        with:
-          profile: minimal
-          toolchain: stable
-          override: true
+      - name: Install Rust
+        uses: dtolnay/rust-toolchain@stable
       - uses: Swatinem/rust-cache@v1
       - run: rustup component add rustfmt
-      - uses: actions-rs/cargo@v1
-        with:
-          command: fmt
-          args: --all -- --check
+      - run: cargo fmt --all -- --check
 
   # clippy:
   #  name: Clippy

+ 24 - 0
packages/core/compile_tests/props_safety_temporary_values.rs

@@ -0,0 +1,24 @@
+use dioxus::prelude::*;
+
+fn main() {}
+
+fn app(cx: Scope) -> Element {
+    let count = vec![1, 2, 3];
+
+    render! {
+        unsafe_child_component {
+            borrowed: &count
+        }
+    }
+}
+
+#[derive(Props)]
+struct Testing<'a> {
+    borrowed: &'a Vec<u32>,
+}
+
+fn unsafe_child_component<'a>(cx: Scope<'a, Testing<'a>>) -> Element<'a> {
+    cx.render(rsx! {
+        div { "{cx.props.borrowed:?}" }
+    })
+}

+ 12 - 0
packages/core/compile_tests/props_safety_temporary_values.stderr

@@ -0,0 +1,12 @@
+error[E0515]: cannot return value referencing local variable `count`
+  --> compile_tests/props_safety_temporary_values.rs:8:5
+   |
+8  | /     render! {
+9  | |         unsafe_child_component {
+10 | |             borrowed: &count
+   | |                       ------ `count` is borrowed here
+11 | |         }
+12 | |     }
+   | |_____^ returns a value referencing data owned by the current function
+   |
+   = note: this error originates in the macro `render` (in Nightly builds, run with -Z macro-backtrace for more info)

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

@@ -143,7 +143,7 @@ pub struct EventHandler<'bump, T = ()> {
 impl<T> Default for EventHandler<'_, T> {
     fn default() -> Self {
         Self {
-            origin: ScopeId(0),
+            origin: ScopeId::ROOT,
             callback: Default::default(),
         }
     }

+ 1 - 0
packages/core/src/properties.rs

@@ -79,4 +79,5 @@ pub fn fc_to_builder<'a, T: Properties + 'a>(_: fn(Scope<'a, T>) -> Element<'a>)
 fn unsafe_props_fail() {
     let t = trybuild::TestCases::new();
     t.compile_fail("compile_tests/props_safety.rs");
+    t.compile_fail("compile_tests/props_safety_temporary_values.rs");
 }

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

@@ -179,7 +179,7 @@ impl ScopeContext {
     pub fn provide_root_context<T: 'static + Clone>(&self, context: T) -> T {
         with_runtime(|runtime| {
             runtime
-                .get_context(ScopeId(0))
+                .get_context(ScopeId::ROOT)
                 .unwrap()
                 .provide_context(context)
         })
@@ -203,7 +203,7 @@ impl ScopeContext {
     /// This is good for tasks that need to be run after the component has been dropped.
     pub fn spawn_forever(&self, fut: impl Future<Output = ()> + 'static) -> TaskId {
         // The root scope will never be unmounted so we can just add the task at the top of the app
-        let id = self.tasks.spawn(ScopeId(0), fut);
+        let id = self.tasks.spawn(ScopeId::ROOT, fut);
 
         // wake up the scheduler if it is sleeping
         self.tasks

+ 18 - 1
packages/core/src/scopes.rs

@@ -63,6 +63,21 @@ impl<'a, T> std::ops::Deref for Scoped<'a, T> {
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
 pub struct ScopeId(pub usize);
 
+impl ScopeId {
+    /// The root ScopeId.
+    ///
+    /// This scope will last for the entire duration of your app, making it convenient for long-lived state
+    /// that is created dynamically somewhere down the component tree.
+    ///
+    /// # Example
+    ///
+    /// ```rust, ignore
+    /// use dioxus_signals::*;
+    /// let my_persistent_state = Signal::new_in_scope(ScopeId::ROOT, String::new());
+    /// ```
+    pub const ROOT: ScopeId = ScopeId(0);
+}
+
 /// A component's state separate from its props.
 ///
 /// This struct exists to provide a common interface for all scopes without relying on generics.
@@ -424,7 +439,9 @@ impl<'src> ScopeState {
         fn_name: &'static str,
     ) -> DynamicNode<'src>
     where
-        P: Properties + 'child,
+        // The properties must be valid until the next bump frame
+        P: Properties + 'src,
+        // The current bump allocator frame must outlive the child's borrowed props
         'src: 'child,
     {
         let vcomp = VProps::new(component, P::memoize, props);

+ 5 - 5
packages/core/src/virtual_dom.rs

@@ -274,7 +274,7 @@ impl VirtualDom {
         );
 
         // Unlike react, we provide a default error boundary that just renders the error as a string
-        root.provide_context(Rc::new(ErrorBoundary::new(ScopeId(0))));
+        root.provide_context(Rc::new(ErrorBoundary::new(ScopeId::ROOT)));
 
         // the root element is always given element ID 0 since it's the container for the entire tree
         dom.elements.insert(None);
@@ -293,7 +293,7 @@ impl VirtualDom {
     ///
     /// This scope has a ScopeId of 0 and is the root of the tree
     pub fn base_scope(&self) -> &ScopeState {
-        self.get_scope(ScopeId(0)).unwrap()
+        self.get_scope(ScopeId::ROOT).unwrap()
     }
 
     /// Build the virtualdom with a global context inserted into the base scope
@@ -552,10 +552,10 @@ impl VirtualDom {
     /// ```
     pub fn rebuild(&mut self) -> Mutations {
         let _runtime = RuntimeGuard::new(self.runtime.clone());
-        match unsafe { self.run_scope(ScopeId(0)).extend_lifetime_ref() } {
+        match unsafe { self.run_scope(ScopeId::ROOT).extend_lifetime_ref() } {
             // Rebuilding implies we append the created elements to the root
             RenderReturn::Ready(node) => {
-                let m = self.create_scope(ScopeId(0), node);
+                let m = self.create_scope(ScopeId::ROOT, node);
                 self.mutations.edits.push(Mutation::AppendChildren {
                     id: ElementId(0),
                     m,
@@ -668,6 +668,6 @@ impl VirtualDom {
 impl Drop for VirtualDom {
     fn drop(&mut self) {
         // Simply drop this scope which drops all of its children
-        self.drop_scope(ScopeId(0), true);
+        self.drop_scope(ScopeId::ROOT, true);
     }
 }

+ 4 - 4
packages/core/tests/attr_cleanup.rs

@@ -34,7 +34,7 @@ fn attrs_cycle() {
         ]
     );
 
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().santize().edits,
         [
@@ -56,7 +56,7 @@ fn attrs_cycle() {
         ]
     );
 
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().santize().edits,
         [
@@ -65,7 +65,7 @@ fn attrs_cycle() {
         ]
     );
 
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().santize().edits,
         [
@@ -88,7 +88,7 @@ fn attrs_cycle() {
     );
 
     // we take the node taken by attributes since we reused it
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().santize().edits,
         [

+ 1 - 1
packages/core/tests/bubble_error.rs

@@ -24,7 +24,7 @@ fn bubbles_error() {
         let _edits = dom.rebuild().santize();
     }
 
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
 
     _ = dom.render_immediate();
 }

+ 3 - 3
packages/core/tests/context_api.rs

@@ -27,11 +27,11 @@ fn state_shares() {
         ]
     );
 
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     _ = dom.render_immediate();
     assert_eq!(dom.base_scope().consume_context::<i32>().unwrap(), 1);
 
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     _ = dom.render_immediate();
     assert_eq!(dom.base_scope().consume_context::<i32>().unwrap(), 2);
 
@@ -41,7 +41,7 @@ fn state_shares() {
         [SetText { value: "Value is 2", id: ElementId(1,) },]
     );
 
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     dom.mark_dirty(ScopeId(2));
     let edits = dom.render_immediate();
     assert_eq!(

+ 3 - 3
packages/core/tests/cycle.rs

@@ -23,7 +23,7 @@ fn cycling_elements() {
         );
     }
 
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().santize().edits,
         [
@@ -33,7 +33,7 @@ fn cycling_elements() {
     );
 
     // notice that the IDs cycle back to ElementId(1), preserving a minimal memory footprint
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().santize().edits,
         [
@@ -42,7 +42,7 @@ fn cycling_elements() {
         ]
     );
 
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().santize().edits,
         [

+ 3 - 3
packages/core/tests/diff_component.rs

@@ -75,7 +75,7 @@ fn component_swap() {
         );
     }
 
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().santize().edits,
         [
@@ -84,7 +84,7 @@ fn component_swap() {
         ]
     );
 
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().santize().edits,
         [
@@ -93,7 +93,7 @@ fn component_swap() {
         ]
     );
 
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().santize().edits,
         [

+ 7 - 7
packages/core/tests/diff_element.rs

@@ -12,19 +12,19 @@ fn text_diff() {
     let mut vdom = VirtualDom::new(app);
     _ = vdom.rebuild();
 
-    vdom.mark_dirty(ScopeId(0));
+    vdom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         vdom.render_immediate().edits,
         [SetText { value: "hello 1", id: ElementId(2) }]
     );
 
-    vdom.mark_dirty(ScopeId(0));
+    vdom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         vdom.render_immediate().edits,
         [SetText { value: "hello 2", id: ElementId(2) }]
     );
 
-    vdom.mark_dirty(ScopeId(0));
+    vdom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         vdom.render_immediate().edits,
         [SetText { value: "hello 3", id: ElementId(2) }]
@@ -46,7 +46,7 @@ fn element_swap() {
     let mut vdom = VirtualDom::new(app);
     _ = vdom.rebuild();
 
-    vdom.mark_dirty(ScopeId(0));
+    vdom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         vdom.render_immediate().santize().edits,
         [
@@ -55,7 +55,7 @@ fn element_swap() {
         ]
     );
 
-    vdom.mark_dirty(ScopeId(0));
+    vdom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         vdom.render_immediate().santize().edits,
         [
@@ -64,7 +64,7 @@ fn element_swap() {
         ]
     );
 
-    vdom.mark_dirty(ScopeId(0));
+    vdom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         vdom.render_immediate().santize().edits,
         [
@@ -73,7 +73,7 @@ fn element_swap() {
         ]
     );
 
-    vdom.mark_dirty(ScopeId(0));
+    vdom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         vdom.render_immediate().santize().edits,
         [

+ 12 - 12
packages/core/tests/diff_keyed_list.rs

@@ -39,7 +39,7 @@ fn keyed_diffing_out_of_order() {
         );
     }
 
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().edits,
         [
@@ -64,7 +64,7 @@ fn keyed_diffing_out_of_order_adds() {
 
     _ = dom.rebuild();
 
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().edits,
         [
@@ -90,7 +90,7 @@ fn keyed_diffing_out_of_order_adds_3() {
 
     _ = dom.rebuild();
 
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().edits,
         [
@@ -116,7 +116,7 @@ fn keyed_diffing_out_of_order_adds_4() {
 
     _ = dom.rebuild();
 
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().edits,
         [
@@ -142,7 +142,7 @@ fn keyed_diffing_out_of_order_adds_5() {
 
     _ = dom.rebuild();
 
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().edits,
         [
@@ -167,7 +167,7 @@ fn keyed_diffing_additions() {
 
     _ = dom.rebuild();
 
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().santize().edits,
         [
@@ -192,7 +192,7 @@ fn keyed_diffing_additions_and_moves_on_ends() {
 
     _ = dom.rebuild();
 
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().santize().edits,
         [
@@ -222,7 +222,7 @@ fn keyed_diffing_additions_and_moves_in_middle() {
     _ = dom.rebuild();
 
     // LIS: 4, 5, 6
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().santize().edits,
         [
@@ -256,7 +256,7 @@ fn controlled_keyed_diffing_out_of_order() {
     _ = dom.rebuild();
 
     // LIS: 5, 6
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().santize().edits,
         [
@@ -289,7 +289,7 @@ fn controlled_keyed_diffing_out_of_order_max_test() {
 
     _ = dom.rebuild();
 
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().santize().edits,
         [
@@ -318,7 +318,7 @@ fn remove_list() {
 
     _ = dom.rebuild();
 
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().santize().edits,
         [
@@ -343,7 +343,7 @@ fn no_common_keys() {
 
     _ = dom.rebuild();
 
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().santize().edits,
         [

+ 18 - 18
packages/core/tests/diff_unkeyed_list.rs

@@ -27,7 +27,7 @@ fn list_creates_one_by_one() {
     );
 
     // Rendering the first item should replace the placeholder with an element
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().santize().edits,
         [
@@ -38,7 +38,7 @@ fn list_creates_one_by_one() {
     );
 
     // Rendering the next item should insert after the previous
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().santize().edits,
         [
@@ -49,7 +49,7 @@ fn list_creates_one_by_one() {
     );
 
     // ... and again!
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().santize().edits,
         [
@@ -60,7 +60,7 @@ fn list_creates_one_by_one() {
     );
 
     // once more
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().santize().edits,
         [
@@ -107,14 +107,14 @@ fn removes_one_by_one() {
 
     // Remove div(3)
     // Rendering the first item should replace the placeholder with an element
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().santize().edits,
         [Remove { id: ElementId(6) }]
     );
 
     // Remove div(2)
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().santize().edits,
         [Remove { id: ElementId(4) }]
@@ -122,7 +122,7 @@ fn removes_one_by_one() {
 
     // Remove div(1) and replace with a placeholder
     // todo: this should just be a remove with no placeholder
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().santize().edits,
         [
@@ -133,7 +133,7 @@ fn removes_one_by_one() {
 
     // load the 3 and replace the placeholder
     // todo: this should actually be append to, but replace placeholder is fine for now
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().santize().edits,
         [
@@ -170,7 +170,7 @@ fn list_shrink_multiroot() {
         ]
     );
 
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().santize().edits,
         [
@@ -182,7 +182,7 @@ fn list_shrink_multiroot() {
         ]
     );
 
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().santize().edits,
         [
@@ -194,7 +194,7 @@ fn list_shrink_multiroot() {
         ]
     );
 
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().santize().edits,
         [
@@ -249,19 +249,19 @@ fn removes_one_by_one_multiroot() {
         ]
     );
 
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().santize().edits,
         [Remove { id: ElementId(10) }, Remove { id: ElementId(12) }]
     );
 
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().santize().edits,
         [Remove { id: ElementId(6) }, Remove { id: ElementId(8) }]
     );
 
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     assert_eq!(
         dom.render_immediate().santize().edits,
         [
@@ -328,7 +328,7 @@ fn remove_many() {
     }
 
     {
-        dom.mark_dirty(ScopeId(0));
+        dom.mark_dirty(ScopeId::ROOT);
         let edits = dom.render_immediate().santize();
         assert_eq!(
             edits.edits,
@@ -341,7 +341,7 @@ fn remove_many() {
     }
 
     {
-        dom.mark_dirty(ScopeId(0));
+        dom.mark_dirty(ScopeId::ROOT);
         let edits = dom.render_immediate().santize();
         assert_eq!(
             edits.edits,
@@ -360,7 +360,7 @@ fn remove_many() {
     }
 
     {
-        dom.mark_dirty(ScopeId(0));
+        dom.mark_dirty(ScopeId::ROOT);
         let edits = dom.render_immediate().santize();
         assert_eq!(
             edits.edits,
@@ -376,7 +376,7 @@ fn remove_many() {
     }
 
     {
-        dom.mark_dirty(ScopeId(0));
+        dom.mark_dirty(ScopeId::ROOT);
         let edits = dom.render_immediate().santize();
         assert_eq!(
             edits.edits,

+ 8 - 8
packages/core/tests/lifecycle.rs

@@ -58,7 +58,7 @@ fn events_generate() {
 
     dom.handle_event("click", Rc::new(MouseData::default()), ElementId(1), true);
 
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     let edits = dom.render_immediate();
 
     assert_eq!(
@@ -107,7 +107,7 @@ fn events_generate() {
 //     );
 
 //     assert_eq!(
-//         dom.hard_diff(ScopeId(0)).edits,
+//         dom.hard_diff(ScopeId::ROOT).edits,
 //         [
 //             CreateElement { root: Some(2), tag: "div", children: 0 },
 //             ReplaceWith { root: Some(1), nodes: vec![2] }
@@ -115,7 +115,7 @@ fn events_generate() {
 //     );
 
 //     assert_eq!(
-//         dom.hard_diff(ScopeId(0)).edits,
+//         dom.hard_diff(ScopeId::ROOT).edits,
 //         [
 //             CreateTextNode { root: Some(1), text: "Text2" },
 //             ReplaceWith { root: Some(2), nodes: vec![1] }
@@ -124,7 +124,7 @@ fn events_generate() {
 
 //     // child {}
 //     assert_eq!(
-//         dom.hard_diff(ScopeId(0)).edits,
+//         dom.hard_diff(ScopeId::ROOT).edits,
 //         [
 //             CreateElement { root: Some(2), tag: "h1", children: 0 },
 //             ReplaceWith { root: Some(1), nodes: vec![2] }
@@ -133,7 +133,7 @@ fn events_generate() {
 
 //     // placeholder
 //     assert_eq!(
-//         dom.hard_diff(ScopeId(0)).edits,
+//         dom.hard_diff(ScopeId::ROOT).edits,
 //         [
 //             CreatePlaceholder { root: Some(1) },
 //             ReplaceWith { root: Some(2), nodes: vec![1] }
@@ -141,7 +141,7 @@ fn events_generate() {
 //     );
 
 //     assert_eq!(
-//         dom.hard_diff(ScopeId(0)).edits,
+//         dom.hard_diff(ScopeId::ROOT).edits,
 //         [
 //             CreateTextNode { root: Some(2), text: "text 3" },
 //             ReplaceWith { root: Some(1), nodes: vec![2] }
@@ -149,7 +149,7 @@ fn events_generate() {
 //     );
 
 //     assert_eq!(
-//         dom.hard_diff(ScopeId(0)).edits,
+//         dom.hard_diff(ScopeId::ROOT).edits,
 //         [
 //             CreateTextNode { text: "text 0", root: Some(1) },
 //             CreateTextNode { text: "text 1", root: Some(3) },
@@ -158,7 +158,7 @@ fn events_generate() {
 //     );
 
 //     assert_eq!(
-//         dom.hard_diff(ScopeId(0)).edits,
+//         dom.hard_diff(ScopeId::ROOT).edits,
 //         [
 //             CreateElement { tag: "h1", root: Some(2), children: 0 },
 //             ReplaceWith { root: Some(1), nodes: vec![2] },

+ 6 - 6
packages/core/tests/miri_simple.rs

@@ -11,7 +11,7 @@ fn app_drops() {
     let mut dom = VirtualDom::new(app);
 
     _ = dom.rebuild();
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     _ = dom.render_immediate();
 }
 
@@ -31,7 +31,7 @@ fn hooks_drop() {
     let mut dom = VirtualDom::new(app);
 
     _ = dom.rebuild();
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     _ = dom.render_immediate();
 }
 
@@ -58,7 +58,7 @@ fn contexts_drop() {
     let mut dom = VirtualDom::new(app);
 
     _ = dom.rebuild();
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     _ = dom.render_immediate();
 }
 
@@ -77,7 +77,7 @@ fn tasks_drop() {
     let mut dom = VirtualDom::new(app);
 
     _ = dom.rebuild();
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     _ = dom.render_immediate();
 }
 
@@ -91,7 +91,7 @@ fn root_props_drop() {
     );
 
     _ = dom.rebuild();
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     _ = dom.render_immediate();
 }
 
@@ -121,7 +121,7 @@ fn diffing_drops_old() {
 
     let mut dom = VirtualDom::new(app);
     _ = dom.rebuild();
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
 
     _ = dom.render_immediate();
 }

+ 8 - 8
packages/core/tests/miri_stress.rs

@@ -62,7 +62,7 @@ fn test_memory_leak() {
     _ = dom.rebuild();
 
     for _ in 0..5 {
-        dom.mark_dirty(ScopeId(0));
+        dom.mark_dirty(ScopeId::ROOT);
         _ = dom.render_immediate();
     }
 }
@@ -97,13 +97,13 @@ fn memo_works_properly() {
 
     _ = dom.rebuild();
     // todo!()
-    // dom.hard_diff(ScopeId(0));
-    // dom.hard_diff(ScopeId(0));
-    // dom.hard_diff(ScopeId(0));
-    // dom.hard_diff(ScopeId(0));
-    // dom.hard_diff(ScopeId(0));
-    // dom.hard_diff(ScopeId(0));
-    // dom.hard_diff(ScopeId(0));
+    // dom.hard_diff(ScopeId::ROOT);
+    // dom.hard_diff(ScopeId::ROOT);
+    // dom.hard_diff(ScopeId::ROOT);
+    // dom.hard_diff(ScopeId::ROOT);
+    // dom.hard_diff(ScopeId::ROOT);
+    // dom.hard_diff(ScopeId::ROOT);
+    // dom.hard_diff(ScopeId::ROOT);
 }
 
 #[test]

+ 2 - 2
packages/native-core/src/utils/persistant_iterator.rs

@@ -354,7 +354,7 @@ fn persist_removes() {
     // "3"
     iter2.next(&rdom).id();
 
-    vdom.mark_dirty(ScopeId(0));
+    vdom.mark_dirty(ScopeId::ROOT);
     let update = vdom.render_immediate();
     println!("{update:#?}");
     dioxus_state.apply_mutations(&mut rdom, update);
@@ -419,7 +419,7 @@ fn persist_instertions_before() {
     // "2"
     iter.next(&rdom).id();
 
-    vdom.mark_dirty(ScopeId(0));
+    vdom.mark_dirty(ScopeId::ROOT);
     let update = vdom.render_immediate();
     dioxus_state.apply_mutations(&mut rdom, update);
 

+ 2 - 0
packages/router/examples/static_generation.rs

@@ -30,6 +30,8 @@ async fn main() {
             .join("\n")
     );
 
+    // This function is available if you enable the ssr feature
+    // on the dioxus_router crate.
     pre_cache_static_routes::<Route, _>(
         &mut renderer,
         &DefaultRenderer {

+ 1 - 1
packages/signals/tests/create.rs

@@ -51,7 +51,7 @@ fn drop_signals() {
     }
 
     let _ = dom.rebuild().santize();
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     dom.render_immediate();
 
     fn create_without_cx() -> Signal<String> {

+ 2 - 2
packages/signals/tests/selector.rs

@@ -124,7 +124,7 @@ fn memos_prevents_component_rerun() {
     }
 
     let _ = dom.rebuild().santize();
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     dom.render_immediate();
 
     {
@@ -133,7 +133,7 @@ fn memos_prevents_component_rerun() {
         assert_eq!(current_counter.effect, 2);
     }
 
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     dom.render_immediate();
     dom.render_immediate();
 

+ 1 - 1
packages/signals/tests/subscribe.rs

@@ -77,7 +77,7 @@ fn reading_subscribes() {
         }
     }
 
-    dom.mark_dirty(ScopeId(0));
+    dom.mark_dirty(ScopeId::ROOT);
     dom.render_immediate();
     dom.render_immediate();
 

+ 1 - 1
packages/ssr/src/renderer.rs

@@ -40,7 +40,7 @@ impl Renderer {
     }
 
     pub fn render_to(&mut self, buf: &mut impl Write, dom: &VirtualDom) -> std::fmt::Result {
-        self.render_scope(buf, dom, ScopeId(0))
+        self.render_scope(buf, dom, ScopeId::ROOT)
     }
 
     pub fn render_scope(