1
0
Эх сурвалжийг харах

Merge branch 'master' into bump-wry

ealmloff 1 жил өмнө
parent
commit
ea69811e70
97 өөрчлөгдсөн 662 нэмэгдсэн , 709 устгасан
  1. 1 1
      .github/workflows/cli_release.yml
  2. 1 1
      .github/workflows/docs stable.yml
  3. 1 1
      .github/workflows/docs.yml
  4. 6 6
      .github/workflows/main.yml
  5. 1 1
      .github/workflows/miri.yml
  6. 1 1
      .github/workflows/playwright.yml
  7. 2 1
      Cargo.toml
  8. 1 1
      docs/guide/src/en/getting_started/web.md
  9. 6 5
      examples/PWA-example/README.md
  10. 9 1
      packages/autofmt/src/collect_macros.rs
  11. 4 5
      packages/cli/Cargo.toml
  12. 21 18
      packages/cli/Dioxus.toml
  13. 44 16
      packages/cli/README.md
  14. 1 1
      packages/cli/docs/book.toml
  15. 9 14
      packages/cli/docs/src/SUMMARY.md
  16. 0 30
      packages/cli/docs/src/cmd/README.md
  17. 0 56
      packages/cli/docs/src/cmd/build.md
  18. 0 27
      packages/cli/docs/src/cmd/clean.md
  19. 0 70
      packages/cli/docs/src/cmd/serve.md
  20. 0 68
      packages/cli/docs/src/cmd/translate.md
  21. 85 96
      packages/cli/docs/src/configure.md
  22. 9 11
      packages/cli/docs/src/creating.md
  23. 9 8
      packages/cli/docs/src/installation.md
  24. 12 15
      packages/cli/docs/src/introduction.md
  25. 74 13
      packages/cli/docs/src/plugin/README.md
  26. 4 4
      packages/cli/docs/src/plugin/interface/command.md
  27. 7 12
      packages/cli/docs/src/plugin/interface/dirs.md
  28. 11 11
      packages/cli/docs/src/plugin/interface/log.md
  29. 9 6
      packages/cli/docs/src/plugin/interface/network.md
  30. 3 3
      packages/cli/docs/src/plugin/interface/os.md
  31. 14 11
      packages/cli/docs/src/plugin/interface/path.md
  32. 5 6
      packages/cli/src/builder.rs
  33. 1 1
      packages/cli/src/cli/build.rs
  34. 1 1
      packages/cli/src/lib.rs
  35. 2 2
      packages/cli/src/server/web/mod.rs
  36. 1 1
      packages/core/Cargo.toml
  37. 1 1
      packages/core/src/any_props.rs
  38. 7 1
      packages/core/src/diff.rs
  39. 1 1
      packages/core/src/events.rs
  40. 2 2
      packages/core/src/nodes.rs
  41. 1 0
      packages/core/src/scope_arena.rs
  42. 34 7
      packages/core/src/scope_context.rs
  43. 2 1
      packages/core/src/virtual_dom.rs
  44. 3 1
      packages/desktop/Cargo.toml
  45. 2 2
      packages/desktop/src/desktop_context.rs
  46. 1 1
      packages/desktop/src/lib.rs
  47. 1 1
      packages/desktop/src/query.rs
  48. 1 1
      packages/dioxus/Cargo.toml
  49. 1 1
      packages/fermi/Cargo.toml
  50. 4 4
      packages/fermi/src/root.rs
  51. 2 1
      packages/fullstack/Cargo.toml
  52. 3 2
      packages/fullstack/examples/axum-hello-world/Cargo.toml
  53. 2 3
      packages/fullstack/examples/axum-hello-world/src/main.rs
  54. 3 2
      packages/fullstack/examples/salvo-hello-world/Cargo.toml
  55. 2 2
      packages/fullstack/examples/salvo-hello-world/src/main.rs
  56. 3 2
      packages/fullstack/examples/warp-hello-world/Cargo.toml
  57. 2 2
      packages/fullstack/examples/warp-hello-world/src/main.rs
  58. 1 1
      packages/fullstack/src/adapters/axum_adapter.rs
  59. 1 1
      packages/fullstack/src/adapters/salvo_adapter.rs
  60. 3 3
      packages/fullstack/src/adapters/warp_adapter.rs
  61. 1 1
      packages/fullstack/src/hooks/server_cached.rs
  62. 4 4
      packages/fullstack/src/hooks/server_future.rs
  63. 1 1
      packages/fullstack/src/hot_reload.rs
  64. 4 4
      packages/fullstack/src/html_storage/deserialize.rs
  65. 2 2
      packages/fullstack/src/html_storage/mod.rs
  66. 6 1
      packages/fullstack/src/layer.rs
  67. 4 4
      packages/fullstack/src/render.rs
  68. 1 1
      packages/fullstack/src/router.rs
  69. 1 1
      packages/hooks/Cargo.toml
  70. 1 1
      packages/hooks/src/use_on_unmount.rs
  71. 14 7
      packages/hooks/src/use_shared_state.rs
  72. 2 0
      packages/html/src/elements.rs
  73. 1 1
      packages/html/src/events/mouse.rs
  74. 1 1
      packages/liveview/Cargo.toml
  75. 1 1
      packages/liveview/src/query.rs
  76. 7 6
      packages/router-macro/src/lib.rs
  77. 1 1
      packages/router-macro/src/query.rs
  78. 6 3
      packages/router-macro/src/route_tree.rs
  79. 10 5
      packages/router-macro/src/segment.rs
  80. 2 2
      packages/router/Cargo.toml
  81. 1 1
      packages/router/src/components/history_buttons.rs
  82. 1 1
      packages/router/src/components/link.rs
  83. 1 1
      packages/router/src/history/web.rs
  84. 1 1
      packages/router/src/history/web_hash.rs
  85. 2 2
      packages/router/src/incremental.rs
  86. 5 0
      packages/router/src/lib.rs
  87. 119 64
      packages/router/src/routable.rs
  88. 1 1
      packages/signals/Cargo.toml
  89. 3 3
      packages/signals/src/signal.rs
  90. 2 2
      packages/ssr/Cargo.toml
  91. 5 5
      packages/ssr/src/incremental.rs
  92. 2 1
      packages/web/Cargo.toml
  93. 2 2
      packages/web/examples/hydrate.rs
  94. 0 1
      packages/web/src/dom.rs
  95. 1 1
      packages/web/src/eval.rs
  96. 4 4
      packages/web/src/lib.rs
  97. 4 4
      packages/web/src/rehydrate.rs

+ 1 - 1
.github/workflows/cli_release.yml

@@ -29,7 +29,7 @@ jobs:
               toolchain: "1.70.0",
               toolchain: "1.70.0",
             }
             }
     steps:
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
       - name: Install stable
       - name: Install stable
         uses: dtolnay/rust-toolchain@master
         uses: dtolnay/rust-toolchain@master
         with:
         with:

+ 1 - 1
.github/workflows/docs stable.yml

@@ -23,7 +23,7 @@ jobs:
       - name: Setup mdBook
       - name: Setup mdBook
         run: |
         run: |
           cargo install mdbook --git https://github.com/Demonthos/mdBook.git --branch master
           cargo install mdbook --git https://github.com/Demonthos/mdBook.git --branch master
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
 
 
       - name: Build
       - name: Build
         run: cd docs &&
         run: cd docs &&

+ 1 - 1
.github/workflows/docs.yml

@@ -28,7 +28,7 @@ jobs:
       - name: Setup mdBook
       - name: Setup mdBook
         run: |
         run: |
           cargo install mdbook --git https://github.com/Demonthos/mdBook.git --branch master
           cargo install mdbook --git https://github.com/Demonthos/mdBook.git --branch master
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
 
 
       - name: Build
       - name: Build
         run: cd docs &&
         run: cd docs &&

+ 6 - 6
.github/workflows/main.yml

@@ -41,7 +41,7 @@ jobs:
       - uses: Swatinem/rust-cache@v2
       - uses: Swatinem/rust-cache@v2
       - run: sudo apt-get update
       - run: sudo apt-get update
       - run: sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev
       - run: sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
       - run: cargo check --all --examples --tests
       - run: cargo check --all --examples --tests
 
 
   test:
   test:
@@ -56,7 +56,7 @@ jobs:
       - uses: davidB/rust-cargo-make@v1
       - uses: davidB/rust-cargo-make@v1
       - uses: browser-actions/setup-firefox@latest
       - uses: browser-actions/setup-firefox@latest
       - uses: jetli/wasm-pack-action@v0.4.0
       - uses: jetli/wasm-pack-action@v0.4.0
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
       - run: cargo make tests
       - run: cargo make tests
 
 
   fmt:
   fmt:
@@ -67,7 +67,7 @@ jobs:
       - uses: dtolnay/rust-toolchain@stable
       - uses: dtolnay/rust-toolchain@stable
       - uses: Swatinem/rust-cache@v2
       - uses: Swatinem/rust-cache@v2
       - run: rustup component add rustfmt
       - run: rustup component add rustfmt
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
       - run: cargo fmt --all -- --check
       - run: cargo fmt --all -- --check
 
 
   clippy:
   clippy:
@@ -80,7 +80,7 @@ jobs:
       - run: sudo apt-get update
       - run: sudo apt-get update
       - run: sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev
       - run: sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev
       - run: rustup component add clippy
       - run: rustup component add clippy
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
       - run: cargo clippy --workspace --examples --tests -- -D warnings
       - run: cargo clippy --workspace --examples --tests -- -D warnings
 
 
   matrix_test:
   matrix_test:
@@ -124,7 +124,7 @@ jobs:
             }
             }
 
 
     steps:
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
 
 
       - name: install stable
       - name: install stable
         uses: dtolnay/rust-toolchain@master
         uses: dtolnay/rust-toolchain@master
@@ -154,7 +154,7 @@ jobs:
   #     options: --security-opt seccomp=unconfined
   #     options: --security-opt seccomp=unconfined
   #   steps:
   #   steps:
   #     - name: Checkout repository
   #     - name: Checkout repository
-  #       uses: actions/checkout@v3
+  #       uses: actions/checkout@v4
   #     - name: Generate code coverage
   #     - name: Generate code coverage
   #       run: |
   #       run: |
   #         apt-get update &&\
   #         apt-get update &&\

+ 1 - 1
.github/workflows/miri.yml

@@ -69,7 +69,7 @@ jobs:
         if: runner.os == 'Linux'
         if: runner.os == 'Linux'
         run: echo "MIRIFLAGS=-Zmiri-tag-gc=1" >> $GITHUB_ENV
         run: echo "MIRIFLAGS=-Zmiri-tag-gc=1" >> $GITHUB_ENV
 
 
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
       - name: Install Rust ${{ env.rust_nightly }}
       - name: Install Rust ${{ env.rust_nightly }}
         uses: dtolnay/rust-toolchain@master
         uses: dtolnay/rust-toolchain@master
         with:
         with:

+ 1 - 1
.github/workflows/playwright.yml

@@ -19,7 +19,7 @@ jobs:
     runs-on: ubuntu-latest
     runs-on: ubuntu-latest
     steps:
     steps:
       # Do our best to cache the toolchain and node install steps
       # Do our best to cache the toolchain and node install steps
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
       - uses: actions/setup-node@v3
       - uses: actions/setup-node@v3
         with:
         with:
           node-version: 16
           node-version: 16

+ 2 - 1
Cargo.toml

@@ -82,7 +82,8 @@ generational-box = { path = "packages/generational-box" }
 dioxus-hot-reload = { path = "packages/hot-reload", version = "0.4.0" }
 dioxus-hot-reload = { path = "packages/hot-reload", version = "0.4.0" }
 dioxus-fullstack = { path = "packages/fullstack", version = "0.4.1"  }
 dioxus-fullstack = { path = "packages/fullstack", version = "0.4.1"  }
 dioxus_server_macro = { path = "packages/server-macro", version = "0.4.1" }
 dioxus_server_macro = { path = "packages/server-macro", version = "0.4.1" }
-log = "0.4.19"
+tracing = "0.1.37"
+tracing-futures = "0.2.5"
 tokio = "1.28"
 tokio = "1.28"
 slab = "0.4.2"
 slab = "0.4.2"
 futures-channel = "0.3.21"
 futures-channel = "0.3.21"

+ 1 - 1
docs/guide/src/en/getting_started/web.md

@@ -25,7 +25,7 @@ The Web is the best-supported target platform for Dioxus.
 To develop your Dioxus app for the web, you'll need a tool to build and serve your assets. We recommend using [dioxus-cli](https://github.com/DioxusLabs/dioxus/tree/master/packages/cli) which includes a build system, Wasm optimization, a dev server, and support hot reloading:
 To develop your Dioxus app for the web, you'll need a tool to build and serve your assets. We recommend using [dioxus-cli](https://github.com/DioxusLabs/dioxus/tree/master/packages/cli) which includes a build system, Wasm optimization, a dev server, and support hot reloading:
 
 
 ```shell
 ```shell
-cargo install dioxus-cli
+cargo install dioxus-cli --locked
 ```
 ```
 
 
 Make sure the `wasm32-unknown-unknown` target for rust is installed:
 Make sure the `wasm32-unknown-unknown` target for rust is installed:

+ 6 - 5
examples/PWA-example/README.md

@@ -7,12 +7,13 @@ It is also very much usable as a template for your projects, if you're aiming to
 
 
 ## Try the example
 ## Try the example
 
 
-Make sure you have Dioxus CLI installed (if you're unsure, run `cargo install dioxus-cli`).
+Make sure you have Dioxus CLI installed (if you're unsure, run `cargo install dioxus-cli --locked`).
 
 
 You can run `dx serve` in this directory to start the web server locally, or run
 You can run `dx serve` in this directory to start the web server locally, or run
 `dx build --release` to build the project so you can deploy it on a separate web-server.
 `dx build --release` to build the project so you can deploy it on a separate web-server.
 
 
 ## Project Structure
 ## Project Structure
+
 ```
 ```
 ├── Cargo.toml
 ├── Cargo.toml
 ├── Dioxus.toml
 ├── Dioxus.toml
@@ -33,12 +34,12 @@ You can run `dx serve` in this directory to start the web server locally, or run
 
 
 If you're just getting started with PWAs, here are some useful resources:
 If you're just getting started with PWAs, here are some useful resources:
 
 
-* [PWABuilder docs](https://docs.pwabuilder.com/#/)
-* [MDN article on PWAs](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps)
+- [PWABuilder docs](https://docs.pwabuilder.com/#/)
+- [MDN article on PWAs](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps)
 
 
 For service worker scripting (in JavaScript):
 For service worker scripting (in JavaScript):
 
 
-* [Service worker guide from PWABuilder](https://docs.pwabuilder.com/#/home/sw-intro)
-* [Service worker examples, also from PWABuilder](https://github.com/pwa-builder/pwabuilder-serviceworkers)
+- [Service worker guide from PWABuilder](https://docs.pwabuilder.com/#/home/sw-intro)
+- [Service worker examples, also from PWABuilder](https://github.com/pwa-builder/pwabuilder-serviceworkers)
 
 
 If you want to stay as close to 100% Rust as possible, you can try using [wasi-worker](https://github.com/dunnock/wasi-worker) to replace the JS service worker file. The JSON manifest will still be required though.
 If you want to stay as close to 100% Rust as possible, you can try using [wasi-worker](https://github.com/dunnock/wasi-worker) to replace the JS service worker file. The JSON manifest will still be required though.

+ 9 - 1
packages/autofmt/src/collect_macros.rs

@@ -17,7 +17,15 @@ struct MacroCollector<'a, 'b> {
 
 
 impl<'a, 'b> Visit<'b> for MacroCollector<'a, 'b> {
 impl<'a, 'b> Visit<'b> for MacroCollector<'a, 'b> {
     fn visit_macro(&mut self, i: &'b Macro) {
     fn visit_macro(&mut self, i: &'b Macro) {
-        self.macros.push(i);
+        if let Some("rsx" | "render") = i
+            .path
+            .segments
+            .last()
+            .map(|i| i.ident.to_string())
+            .as_deref()
+        {
+            self.macros.push(i)
+        }
     }
     }
 }
 }
 
 

+ 4 - 5
packages/cli/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 [package]
 name = "dioxus-cli"
 name = "dioxus-cli"
-version = { workspace = true }
+version = "0.4.1"
 authors = ["Jonathan Kelley"]
 authors = ["Jonathan Kelley"]
 edition = "2021"
 edition = "2021"
 description = "CLI tool for developing, testing, and publishing Dioxus apps"
 description = "CLI tool for developing, testing, and publishing Dioxus apps"
@@ -36,7 +36,7 @@ chrono = "0.4.19"
 anyhow = "1.0.53"
 anyhow = "1.0.53"
 hyper = "0.14.17"
 hyper = "0.14.17"
 hyper-rustls = "0.23.2"
 hyper-rustls = "0.23.2"
-indicatif = "0.17.0-rc.11"
+indicatif = "0.17.5"
 subprocess = "0.2.9"
 subprocess = "0.2.9"
 
 
 axum = { version = "0.5.1", features = ["ws", "headers"] }
 axum = { version = "0.5.1", features = ["ws", "headers"] }
@@ -75,11 +75,10 @@ gitignore = "1.0.7"
 open = "4.1.0"
 open = "4.1.0"
 cargo-generate = "0.18"
 cargo-generate = "0.18"
 toml_edit = "0.19.11"
 toml_edit = "0.19.11"
-# dioxus-rsx = "0.0.1"
 
 
 # bundling
 # bundling
-tauri-bundler = { version = "1.2", features = ["native-tls-vendored"] }
-tauri-utils = "1.3"
+tauri-bundler = { version = "=1.3.0", features = ["native-tls-vendored"] }
+tauri-utils = "=1.4.*"
 
 
 dioxus-autofmt = { workspace = true }
 dioxus-autofmt = { workspace = true }
 dioxus-check = { workspace = true }
 dioxus-check = { workspace = true }

+ 21 - 18
packages/cli/Dioxus.toml

@@ -1,29 +1,31 @@
 [application]
 [application]
 
 
-# dioxus project name
-name = "dioxus-cli"
+# App name
+name = "project_name"
 
 
-# default platfrom
-# you can also use `dx serve/build --platform XXX` to use other platform
-# value: web | desktop
-default_platform = "desktop"
+# The Dioxus platform to default to
+default_platform = "web"
 
 
-# Web `build` & `serve` dist path
+# `build` & `serve` output path
 out_dir = "dist"
 out_dir = "dist"
 
 
-# resource (static) file folder
+# The static resource path
 asset_dir = "public"
 asset_dir = "public"
 
 
 [web.app]
 [web.app]
 
 
 # HTML title tag content
 # HTML title tag content
-title = "dioxus | ⛺"
+title = "project_name"
 
 
 [web.watcher]
 [web.watcher]
 
 
-watch_path = ["src"]
+# When watcher is triggered, regenerate the `index.html`
+reload_html = true
 
 
-# include `assets` in web platform
+# Which files or dirs will be monitored
+watch_path = ["src", "public"]
+
+# Include style or script assets
 [web.resource]
 [web.resource]
 
 
 # CSS style file
 # CSS style file
@@ -34,12 +36,13 @@ script = []
 
 
 [web.resource.dev]
 [web.resource.dev]
 
 
-# Javascript code file
-# serve: [dev-server] only
-script = []
+# Same as [web.resource], but for development servers
 
 
-[application.tools]
+# CSS style file
+style = []
+
+# JavaScript files
+script = []
 
 
-# use binaryen.wasm-opt for output Wasm file
-# binaryen just will trigger in `web` platform
-binaryen = { wasm_opt = true }
+[[web.proxy]]
+backend = "http://localhost:8000/api/"

+ 44 - 16
packages/cli/README.md

@@ -1,43 +1,71 @@
-<div align="center">
-  <h1>📦✨ Dioxus CLI </h1>
+<div style="text-align: center">
+  <h1>📦✨ Dioxus CLI</h1>
   <p><strong>Tooling to supercharge Dioxus projects</strong></p>
   <p><strong>Tooling to supercharge Dioxus projects</strong></p>
 </div>
 </div>
-**dioxus-cli** (inspired by wasm-pack and webpack) is a tool for getting Dioxus projects up and running.
-It handles all build, bundling, development and publishing to simplify web development.
 
 
+The **dioxus-cli** (inspired by wasm-pack and webpack) is a tool for getting Dioxus projects up and running.
+It handles all building, bundling, development and publishing to simplify development.
 
 
 ## Installation
 ## Installation
 
 
-### Install stable version
+### Install the stable version (recommended)
+
 ```
 ```
-cargo install dioxus-cli
+cargo install dioxus-cli --locked
 ```
 ```
-### Install from git repository
+
+### Install the latest development build through git
+
+To get the latest bug fixes and features, you can install the development version from git.
+However, this is not fully tested.
+That means you're probably going to have more bugs despite having the latest bug fixes.
+
 ```
 ```
 cargo install --git https://github.com/DioxusLabs/dioxus dioxus-cli
 cargo install --git https://github.com/DioxusLabs/dioxus dioxus-cli
 ```
 ```
+
+This will download the CLI from the master branch,
+and install it in Cargo's global binary directory (`~/.cargo/bin/` by default).
+
 ### Install from local folder
 ### Install from local folder
+
 ```
 ```
 cargo install --path . --debug
 cargo install --path . --debug
 ```
 ```
 
 
+## Get started
 
 
-## Get Started
-
-Use `dx create project-name` to initialize a new Dioxus project. <br>
-
+Use `dx create project-name` to initialize a new Dioxus project.
 It will be cloned from the [dioxus-template](https://github.com/DioxusLabs/dioxus-template) repository.
 It will be cloned from the [dioxus-template](https://github.com/DioxusLabs/dioxus-template) repository.
 
 
-<br>
-
 Alternatively, you can specify the template path:
 Alternatively, you can specify the template path:
 
 
 ```
 ```
 dx create hello --template gh:dioxuslabs/dioxus-template
 dx create hello --template gh:dioxuslabs/dioxus-template
 ```
 ```
 
 
-## Dioxus Config File
+Run `dx --help` for a list of all the available commands.
+Furthermore, you can run `dx <command> --help` to get help with a specific command.
+
+## Dioxus config file
+
+You can use the `Dioxus.toml` file for further configuration.
+Some fields are mandatory, but the CLI tool will tell you which ones are missing.
+You can create a `Dioxus.toml` with all fields already set using `dx config init project-name`,
+or you can use this bare-bones template (only mandatory fields) to get started:
 
 
-Dioxus CLI will use `Dioxus.toml` file to Identify some project info and switch some cli feature.
+```toml
+[application]
+name = "project-name"
+# Currently supported platforms: web, desktop
+default_platform = "web"
+
+[web.app]
+title = "Hello"
+
+[web.watcher]
+
+[web.resource.dev]
+```
 
 
-You can get more configure information from [Dioxus CLI Document](https://dioxuslabs.com/cli/configure.html).
+The full anatomy of `Dioxus.toml` is shown on the [Dioxus website](https://dioxuslabs.com/learn/0.4/CLI/configure).

+ 1 - 1
packages/cli/docs/book.toml

@@ -3,4 +3,4 @@ authors = ["YuKun Liu"]
 language = "en"
 language = "en"
 multilingual = false
 multilingual = false
 src = "src"
 src = "src"
-title = "Dioxus Cli"
+title = "Dioxus CLI"

+ 9 - 14
packages/cli/docs/src/SUMMARY.md

@@ -2,17 +2,12 @@
 
 
 - [Introduction](./introduction.md)
 - [Introduction](./introduction.md)
 - [Installation](./installation.md)
 - [Installation](./installation.md)
-- [Create a Project](./creating.md)
-- [Configure Project](./configure.md)
-- [Commands](./cmd/README.md)
-  - [Build](./cmd/build.md)
-  - [Serve](./cmd/serve.md)
-  - [Clean](./cmd/clean.md)
-  - [Translate](./cmd/translate.md)
-- [Plugin Development](./plugin/README.md)
-  - [API.Log](./plugin/interface/log.md)
-  - [API.Command](./plugin/interface/command.md)
-  - [API.OS](./plugin/interface/os.md)
-  - [API.Directories](./plugin/interface/dirs.md)
-  - [API.Network](./plugin/interface/network.md)
-  - [API.Path](./plugin/interface/path.md)
+- [Create a project](./creating.md)
+- [Configure a project](./configure.md)
+- [Plugin development](./plugin/README.md)
+  - [API.Log](plugin/interface/log.md)
+  - [API.Command](plugin/interface/command.md)
+  - [API.OS](plugin/interface/os.md)
+  - [API.Directories](plugin/interface/dirs.md)
+  - [API.Network](plugin/interface/network.md)
+  - [API.Path](plugin/interface/path.md)

+ 0 - 30
packages/cli/docs/src/cmd/README.md

@@ -1,30 +0,0 @@
-# Commands
-
-In this chapter we will introduce all `dioxus-cli` commands.
-
-> You can also use `dx --help` to get cli help info.
-
-```
-Build, Bundle & Ship Dioxus Apps
-
-Usage: dx [OPTIONS] <COMMAND>
-
-Commands:
-  build      Build the Rust WASM app and all of its assets
-  translate  Translate some source file into Dioxus code
-  serve      Build, watch & serve the Rust WASM app and all of its assets
-  create     Init a new project for Dioxus
-  clean      Clean output artifacts
-  bundle     Bundle the Rust desktop app and all of its assets
-  version    Print the version of this extension
-  fmt        Format some rsx
-  check      Check the Rust files in the project for issues
-  config     Dioxus config file controls
-  help       Print this message or the help of the given subcommand(s)
-
-Options:
-  -v               Enable verbose logging
-      --bin <BIN>  Specify bin target
-  -h, --help       Print help
-  -V, --version    Print version
-```

+ 0 - 56
packages/cli/docs/src/cmd/build.md

@@ -1,56 +0,0 @@
-# Build
-
-The `dx build` command can help you `pack & build` a dioxus project.
-
-```
-dioxus-build
-Build the Rust WASM app and all of its assets
-
-USAGE:
-    dx build [OPTIONS]
-
-OPTIONS:
-        --example <EXAMPLE>      [default: ""]
-        --platform <PLATFORM>    [default: "default_platform"]
-        --release                [default: false]
-        --bin                    [default: None]
-```
-
-You can use this command to build a project:
-
-```
-dx build --release
-```
-
-## Target platform
-
-Use the `platform` option to choose your target platform:
-
-```
-# for desktop project
-dx build --platform desktop
-```
-
-`platform` currently only supports `desktop` & `web`.
-
-```
-# for web project
-dx build --platform web
-```
-
-## Specify workspace bin
-
-You can add the `--bin` option to select which crate you want Dioxus to build:
-
-```
-dx build --bin app
-```
-
-## Build Example
-
-You can use the `example` option to select a example to build:
-
-```
-# build the `test` example
-dx build --exmaple test
-```

+ 0 - 27
packages/cli/docs/src/cmd/clean.md

@@ -1,27 +0,0 @@
-# Clean
-
-`dx clean` will clear the build artifacts (the out_dir and the cargo cache)
-
-```
-dioxus-clean
-Clean build artifacts
-
-USAGE:
-    dx clean [OPTIONS]
-
-OPTIONS:
-        --bin   [default: None]
-```
-
-# Example
-
-```
-dx clean
-```
-
-# Specify workspace bin
-You can add the `--bin` option to select which crate you want Dioxus to clean artifacts from:
-
-```
-dx clean --bin app
-```

+ 0 - 70
packages/cli/docs/src/cmd/serve.md

@@ -1,70 +0,0 @@
-# Serve
-
-The `dx serve` can start a dev server with hot-reloading
-
-```
-dioxus-serve
-Build, watch & serve the Rust WASM app and all of its assets
-
-USAGE:
-    dx serve [OPTIONS]
-
-OPTIONS:
-        --example <EXAMPLE>      [default: ""]
-        --platform <PLATFORM>    [default: "default_platform"]
-        --release                [default: false]
-        --hot-reload             [default: false]
-        --bin                    [default: None]
-```
-
-You can use this command to build project and start a dev server:
-
-```
-dx serve
-```
-
-## Serve Example
-
-You can use the `example` option to serve a example:
-
-```
-# serve the `test` example
-dx serve --exmaple test
-```
-
-## Specify workspace bin
-
-You can add the `--bin` option to select which crate you want Dioxus to build and serve:
-
-```
-dx serve --bin app
-```
-
-## Open Browser
-
-You can add the `--open` option to open system default browser when server startup:
-
-```
-dx serve --open
-```
-
-## RSX Hot Reloading
-
-You can add the `--hot-reload` flag to enable [rsx hot reloading](https://dioxuslabs.com/docs/0.3/guide/en/getting_started/hot_reload.html). This will allow you to reload some rsx changes without a full recompile:
-
-```
-dx serve --open
-```
-
-## Cross Origin Policy
-
-You can add the `cross-origin-policy` option to change cross-origin header to:
-
-```
-  Cross-Origin-Opener-Policy: same-origin
-  Cross-Origin-Embedder-Policy: require-corp
-```
-
-```
-dx serve --corss-origin-policy
-```

+ 0 - 68
packages/cli/docs/src/cmd/translate.md

@@ -1,68 +0,0 @@
-# Translate
-
-`dx translate` can translate some `html` file into a Dioxus compoent
-
-```
-dioxus-translate
-Translate some source file into a Dioxus component
-
-USAGE:
-    dx translate [OPTIONS] [OUTPUT]
-
-ARGS:
-    <OUTPUT>    Output file, defaults to stdout if not present
-
-OPTIONS:
-    -c, --component      Activate debug mode
-    -f, --file <FILE>    Input file
-```
-
-## Translate HTML to stdout
-
-You can use the `file` option to set path to the `html` file to translate:
-
-```
-dx transtale --file ./index.html
-```
-
-## Output rsx to a file
-
-You can pass a file to the traslate command to set the path to write the output of the command to:
-
-```
-dx translate --file ./index.html component.rsx
-```
-
-## Output rsx to a file
-
-Setting the `component` option will create a compoent from the HTML:
-
-```
-dx translate --file ./index.html --component
-```
-
-## Example
-
-This HTML:
-```html
-<div>
-    <h1> Hello World </h1>
-    <a href="https://dioxuslabs.com/">Link</a>
-</div>
-```
-
-Translates into this Dioxus component:
-
-```rust
-fn component(cx: Scope) -> Element {
-    cx.render(rsx! {
-        div {
-            h1 { "Hello World" },
-            a {
-                href: "https://dioxuslabs.com/",
-                "Link"
-            }
-        }
-    })
-}
-```

+ 85 - 96
packages/cli/docs/src/configure.md

@@ -1,166 +1,155 @@
 # Configure Project
 # Configure Project
 
 
+This chapter will teach you how to configure the CLI with the `Dioxus.toml` file.
+There's an [example](#config-example) which has comments to describe individual keys.
+You can copy that or view this documentation for a more complete learning experience.
 
 
-This chapter will introduce you to how to configure the CLI with your `Dioxus.toml` file
-
-Be aware that if the config file is present in the folder, some fields must be filled out, or the CLI tool will abort. The mandatory [table headers](https://toml.io/en/v1.0.0#table) and keys will have a '✍' sign beside it.
+"🔒" indicates a mandatory item. Some headers are mandatory, but none of the keys inside them are. It might look weird, but it's normal. Simply don't include any keys.
 
 
 ## Structure
 ## Structure
 
 
-The CLI uses a `Dioxus.toml` file in the root of your crate to define some configuration for your `dioxus` project.
-
-### Application ✍
+Each header has it's TOML form directly under it.
 
 
-General application confiration:
+### Application 🔒
 
 
-```
+```toml
 [application]
 [application]
-# configuration
 ```
 ```
-1. ***name*** ✍ - project name & title
-2. ***default_platform*** ✍ - which platform target for this project.
 
 
+Application-wide configuration. Applies to both web and desktop.
+
+1. **name** 🔒 - Project name & title.
+   ```toml
+   name = "my_project"
    ```
    ```
-   name = "my-project"
-   ```
-2. ***default_platform*** - The platform this project targets
-   ```ß
-   # current supported platforms: web, desktop
-   # default: web
+
+2. **default_platform** 🔒 - The platform this project targets
+   ```toml
+   # Currently supported platforms: web, desktop
    default_platform = "web"
    default_platform = "web"
    ```
    ```
-   if you change this to `desktop`, the `dx build` will default building a desktop app
-3. ***out_dir*** - The directory to place the build artifacts from `dx build` or `dx service` into. This is also where the `assets` directory will be copied to
-    ```
+
+3. **out_dir** - The directory to place the build artifacts from `dx build` or `dx serve` into. This is also where the `assets` directory will be copied into.
+    ```toml
     out_dir = "dist"
     out_dir = "dist"
     ```
     ```
-4. ***asset_dir*** - The directory with your static assets. The CLI will automatically copy these assets into the ***out_dir*** after a build/serve.
-   ```
+
+4. **asset_dir** - The directory with your static assets. The CLI will automatically copy these assets into the **out_dir** after a build/serve.
+   ```toml
    asset_dir = "public"
    asset_dir = "public"
    ```
    ```
-5. ***sub_package*** - The sub package in the workspace to build by default
-   ```
+
+5. **sub_package** - The sub package in the workspace to build by default.
+   ```toml
    sub_package = "my-crate"
    sub_package = "my-crate"
    ```
    ```
 
 
-### Web.App ✍
-
-Configeration specific to web applications:
+### Web.App 🔒
 
 
-```
+```toml
 [web.app]
 [web.app]
-# configuration
 ```
 ```
 
 
-1. ***title*** - The title of the web page
-   ```
+Web-specific configuration.
+
+1. **title** - The title of the web page.
+   ```toml
    # HTML title tag content
    # HTML title tag content
-   title = "dioxus app | ⛺"
-   ```
-2. ***base_path*** - The base path to build the appliation for serving at. This can be useful when serving your application in a subdirectory under a domain. For example when building a site to be served on github pages.
+   title = "project_name"
    ```
    ```
+
+2. **base_path** - The base path to build the application for serving at. This can be useful when serving your application in a subdirectory under a domain. For example when building a site to be served on GitHub Pages.
+   ```toml
    # The application will be served at domain.com/my_application/, so we need to modify the base_path to the path where the application will be served
    # The application will be served at domain.com/my_application/, so we need to modify the base_path to the path where the application will be served
    base_path = "my_application"
    base_path = "my_application"
    ```
    ```
 
 
 ### Web.Watcher ✍
 ### Web.Watcher ✍
 
 
-Configeration related to the development server:
-
-```
+```toml
 [web.watcher]
 [web.watcher]
-# configuration
 ```
 ```
 
 
-1. ***reload_html*** - If this is true, the cli will rebuild the index.html file every time the application is rebuilt
-   ```
+Development server configuration.
+
+1. **reload_html** - If this is true, the cli will rebuild the index.html file every time the application is rebuilt
+   ```toml
    reload_html = true
    reload_html = true
    ```
    ```
-2. ***watch_path*** - The files & directories to moniter for changes
-   ```
+
+2. **watch_path** - The files & directories to monitor for changes
+   ```toml
    watch_path = ["src", "public"]
    watch_path = ["src", "public"]
    ```
    ```
-3. ***index_on_404*** - If enabled, Dioxus CLI will serve the root page when a route is not found. *This is needed when serving an application that uses the router*
-   ```
+
+3. **index_on_404** - If enabled, Dioxus will serve the root page when a route is not found.
+*This is needed when serving an application that uses the router*.
+However, when serving your app using something else than Dioxus (e.g. GitHub Pages), you will have to check how to configure it on that platform.
+In GitHub Pages, you can make a copy of `index.html` named `404.html` in the same directory. 
+   ```toml
    index_on_404 = true
    index_on_404 = true
    ```
    ```
 
 
-### Web.Resource ✍
+### Web.Resource 🔒
 
 
-Configeration related to static resources your application uses:
-```
+```toml
 [web.resource]
 [web.resource]
-# configuration
 ```
 ```
 
 
-1. ***style*** - The styles (`.css` files) to include in your application
-   ```
+Static resource configuration.
+
+1. **style** - CSS files to include in your application.
+   ```toml
    style = [
    style = [
-      # include from public_dir.
+      # Include from public_dir.
       "./assets/style.css",
       "./assets/style.css",
-      # or some asset from online cdn.
+      # Or some asset from online cdn.
       "https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.css"
       "https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.css"
    ]
    ]
    ```
    ```
-2. ***script*** - The additional scripts (`.js` files) to include in your application
-    ```
-    style = [
-        # include from public_dir.
-        "./assets/index.js",
-        # or some asset from online cdn.
+
+2. **script** - JavaScript files to include in your application.
+    ```toml
+    script = [
+        # Include from asset_dir.
+        "./public/index.js",
+        # Or from an online CDN.
         "https://cdn.jsdelivr.net/npm/bootstrap/dist/js/bootstrap.js"
         "https://cdn.jsdelivr.net/npm/bootstrap/dist/js/bootstrap.js"
     ]
     ]
    ```
    ```
 
 
-### Web.Resource.Dev 
+### Web.Resource.Dev 🔒
 
 
-Configeration related to static resources your application uses in development:
-```
+```toml
 [web.resource.dev]
 [web.resource.dev]
-# configuration
 ```
 ```
 
 
-1. ***style*** - The styles (`.css` files) to include in your application
-   ```
-   style = [
-      # include from public_dir.
-      "./assets/style.css",
-      # or some asset from online cdn.
-      "https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.css"
-   ]
-   ```
-2. ***script*** - The additional scripts (`.js` files) to include in your application
-    ```
-    style = [
-        # include from public_dir.
-        "./assets/index.js",
-        # or some asset from online cdn.
-        "https://cdn.jsdelivr.net/npm/bootstrap/dist/js/bootstrap.js"
-    ]
-   ```
+This is the same as [`[web.resource]`](#webresource-), but it only works in development servers.
+For example, if you want to include a file in a `dx serve` server, but not a `dx serve --release` server, put it here.
 
 
 ### Web.Proxy
 ### Web.Proxy
 
 
-Configeration related to any proxies your application requires durring development. Proxies will forward requests to a new service
-
-```
+```toml
 [[web.proxy]]
 [[web.proxy]]
-# configuration
 ```
 ```
 
 
-1. ***backend*** - The URL to the server to proxy. The CLI will forward any requests under the backend relative route to the backend instead of returning 404
-   ```
+Configuration related to any proxies your application requires during development. Proxies will forward requests to a new service.
+
+1. **backend** - The URL to the server to proxy. The CLI will forward any requests under the backend relative route to the backend instead of returning 404
+   ```toml
    backend = "http://localhost:8000/api/"
    backend = "http://localhost:8000/api/"
    ```
    ```
-   This will cause any requests made to the dev server with prefix /api/ to be redirected to the backend server at http://localhost:8000. The path and query parameters will be passed on as-is (path rewriting is not currently supported).
+   This will cause any requests made to the dev server with prefix /api/ to be redirected to the backend server at http://localhost:8000. The path and query parameters will be passed on as-is (path rewriting is currently not supported).
 
 
 ## Config example
 ## Config example
 
 
+This includes all fields, mandatory or not.
+
 ```toml
 ```toml
 [application]
 [application]
 
 
-# App (Project) Name
-name = "{{project-name}}"
+# App name
+name = "project_name"
 
 
 # The Dioxus platform to default to
 # The Dioxus platform to default to
 default_platform = "web"
 default_platform = "web"
@@ -168,23 +157,23 @@ default_platform = "web"
 # `build` & `serve` output path
 # `build` & `serve` output path
 out_dir = "dist"
 out_dir = "dist"
 
 
-# the static resource path
+# The static resource path
 asset_dir = "public"
 asset_dir = "public"
 
 
 [web.app]
 [web.app]
 
 
 # HTML title tag content
 # HTML title tag content
-title = "dioxus | ⛺"
+title = "project_name"
 
 
 [web.watcher]
 [web.watcher]
 
 
-# when watcher is triggered, regenerate the `index.html`
+# When watcher is triggered, regenerate the `index.html`
 reload_html = true
 reload_html = true
 
 
-# which files or dirs will be monitored
+# Which files or dirs will be monitored
 watch_path = ["src", "public"]
 watch_path = ["src", "public"]
 
 
-# include `assets` in web platform
+# Include style or script assets
 [web.resource]
 [web.resource]
 
 
 # CSS style file
 # CSS style file
@@ -195,12 +184,12 @@ script = []
 
 
 [web.resource.dev]
 [web.resource.dev]
 
 
-# serve: [dev-server] only
+# Same as [web.resource], but for development servers
 
 
 # CSS style file
 # CSS style file
 style = []
 style = []
 
 
-# Javascript code file
+# JavaScript files
 script = []
 script = []
 
 
 [[web.proxy]]
 [[web.proxy]]

+ 9 - 11
packages/cli/docs/src/creating.md

@@ -1,39 +1,37 @@
 # Create a Project
 # Create a Project
 
 
-Once you have the Dioxus CLI tool installed, you can use it to create dioxus project.
+Once you have the Dioxus CLI installed, you can use it to create your own project!
 
 
 ## Initializing a default project
 ## Initializing a default project
 
 
-First, run the `dx create` command to create a new project ready to be used with Dioxus and the Dioxus CLI:
-
+First, run the `dx create` command to create a new project:
 ```
 ```
 dx create hello-dioxus
 dx create hello-dioxus
 ```
 ```
 
 
-> It will clone a default template from github template: [DioxusLabs/dioxus-template](https://github.com/DioxusLabs/dioxus-template)
-> This default template is use for `web` platform application.
+> It will clone this [template](https://github.com/DioxusLabs/dioxus-template).
+> This default template is used for `web` platform application.
 >
 >
 > You can choose to create your project from a different template by passing the `template` argument:
 > You can choose to create your project from a different template by passing the `template` argument:
 > ```
 > ```
 > dx init hello-dioxus --template=gh:dioxuslabs/dioxus-template
 > dx init hello-dioxus --template=gh:dioxuslabs/dioxus-template
 > ```
 > ```
 
 
-Next, move the current directory into your new project:
+Next, navigate into your new project:
 
 
 ```
 ```
 cd hello-dioxus
 cd hello-dioxus
 ```
 ```
 
 
-> Make sure `wasm32 target` is installed before running the Web project.
-> You can install the wasm target for rust using rustup:
+> Make sure the WASM target is installed before running the projects.
+> You can install the WASM target for rust using rustup:
 > ```
 > ```
 > rustup target add wasm32-unknown-unknown
 > rustup target add wasm32-unknown-unknown
 > ```
 > ```
 
 
-Finally, create serve your project with the Dioxus CLI:
-
+Finally, serve your project:
 ```
 ```
 dx serve
 dx serve
 ```
 ```
 
 
-By default, the CLI serve your site at: [`http://127.0.0.1:8080/`](http://127.0.0.1:8080/)
+By default, the CLI serves your website at [`http://127.0.0.1:8080/`](http://127.0.0.1:8080/).

+ 9 - 8
packages/cli/docs/src/installation.md

@@ -1,22 +1,23 @@
 # Installation
 # Installation
 
 
-Choose any one of the methods below to install the Dioxus CLI:
+## Install the latest development build through git
 
 
-## Install from latest git version
-
-To get the most up to date bug fixes and features of the Dioxus CLI, you can install the development version from git.
+To get the latest bug fixes and features, you can install the development version from git.
 
 
 ```
 ```
 cargo install --git https://github.com/Dioxuslabs/cli
 cargo install --git https://github.com/Dioxuslabs/cli
 ```
 ```
 
 
-This will automatically download `Dioxus-CLI` source from github master branch,
+This will download `Dioxus-CLI` source from GitHub master branch,
 and install it in Cargo's global binary directory (`~/.cargo/bin/` by default).
 and install it in Cargo's global binary directory (`~/.cargo/bin/` by default).
 
 
-## Install from `crates.io` version
+## Install stable through `crates.io`
 
 
-The published version of the Dioxus CLI is updated less often, but should be more stable than the git version of the Dioxus CLI.
+The published version of the Dioxus CLI is updated less often, but is more stable than the git version.
 
 
 ```
 ```
-cargo install dioxus-cli
+cargo install dioxus-cli --locked
 ```
 ```
+
+Run `dx --help` for a list of all the available commands.
+Furthermore, you can run `dx <COMMAND> --help` to get help with a specific command.

+ 12 - 15
packages/cli/docs/src/introduction.md

@@ -1,21 +1,18 @@
 # Introduction
 # Introduction
 
 
-📦✨ **Dioxus-Cli** is a tool to help get dioxus projects off the ground.
-
-![dioxus-logo](https://dioxuslabs.com/guide/images/dioxuslogo_full.png)
-
-It includes `dev server`, `hot reload` and some `quick command` to help you use dioxus.
+The 📦✨ **Dioxus CLI** is a tool to help get Dioxus projects off the ground.
 
 
 ## Features
 ## Features
 
 
+* Build and pack a Dioxus project
+* `html` to `rsx` conversion tool
+* Hot Reload for `web` platform
+* Create a Dioxus project from `git` repo
+* And more!
+<!-- Checkmarks don't render on the website, so I've just made a normal list. You can uncomment this if the website rendering is fixed.
 - [x] `html` to `rsx` conversion tool
 - [x] `html` to `rsx` conversion tool
-- [x] hot reload for `web` platform
-- [x] create dioxus project from `git` repo
-- [x] build & pack dioxus project
-- [ ] autoformat dioxus `rsx` code
-
-## Contributors
-
-Contributors to this guide:
-
-- [mrxiaozhuox](https://github.com/mrxiaozhuox)
+- [x] Hot Reload for `web` platform
+- [x] Create a Dioxus project from `git` repo
+- [x] Build & pack Dioxus project
+- [ ] Automatically format Dioxus `rsx` code
+-->

+ 74 - 13
packages/cli/docs/src/plugin/README.md

@@ -1,24 +1,85 @@
-# CLI Plugin Development
+# CLI Plugin development
 
 
-> For Cli 0.2.0 we will add `plugin-develop` support.
+**IMPORTANT: Ignore this documentation. Plugins are yet to be released and chances are it won't work for you. This is just what plugins *could* look like.**
 
 
-Before the 0.2.0 we use `dx tool` to use & install some plugin, but we think that is not good for extend cli program, some people want tailwind support, some people want sass support, we can't add all this thing in to the cli source code and we don't have time to maintain a lot of tools that user request, so maybe user make plugin by themself is a good choice.
+In the past we used `dx tool` to use and install tools, but it was a flawed system.
+Tools were hard-coded by us, but people want more tools than we could code, so this plugin system was made to let
+anyone develop plugins and use them in Dioxus projects.
 
 
-### Why Lua ?
+Plugin resources:
+* [Source code](https://github.com/DioxusLabs/dioxus/tree/master/packages/cli/src/plugin)
+* [Unofficial Dioxus plugin community](https://github.com/DioxusPluginCommunity). Contains certain plugins you can use right now.
 
 
-We choose `Lua: 5.4` to be the plugin develop language, because cli plugin is not complex, just like a workflow, and user & developer can write some easy code for their plugin. We have **vendored** lua in cli program, and user don't need install lua runtime in their computer, and the lua parser & runtime doesn't take up much disk memory.
+### Why Lua?
 
 
-### Event Management
+We chose Lua `5.4` to be the plugin developing language,
+because it's extremely lightweight, embeddable and easy to learn.
+We installed Lua into the CLI, so you don't need to do it yourself.
 
 
-The plugin library have pre-define some important event you can control:
+Lua resources:
+* [Official website](https://www.lua.org/). You can basically find everything here.
+* [Awesome Lua](https://github.com/LewisJEllis/awesome-lua). Additional resources (such as Lua plugins for your favorite IDE), and other *awesome* tools!
 
 
-- `build.on_start`
-- `build.on_finished`
-- `serve.on_start`
-- `serve.on_rebuild`
-- `serve.on_shutdown`
 
 
-### Plugin Template
+## Creating a plugin
+
+A plugin is just an `init.lua` file.
+You can include other files using `dofile(path)`.
+You need to have a plugin and a manager instance, which you can get using `require`:
+```lua
+local plugin = require("plugin")
+local manager = require("manager")
+```
+
+You need to set some `manager` fields and then initialize the plugin:
+```lua
+manager.name = "My first plugin"
+manager.repository = "https://github.com/john-doe/my-first-plugin" -- The repository URL.
+manager.author = "John Doe <john.doe@example.com>"
+manager.version = "0.1.0"
+plugin.init(manager)
+```
+
+You also need to return the `manager`, which basically represents your plugin:
+```lua
+-- Your code here.
+-- End of file.
+
+manager.serve.interval = 1000
+return manager
+```
+
+And you're ready to go. Now, go and have a look at the stuff below and the API documentation.
+
+### Plugin info
+
+You will encounter this type in the events below. The keys are as follows:
+* `name: string` - The name of the plugin.
+* `repository: string` - The plugin repository URL.
+* `author: string` - The author of the plugin.
+* `version: string` - The plugin version.
+
+### Event management
+
+The plugin library has certain events that you can subscribe to.
+
+* `manager.on_init` - Triggers the first time the plugin is loaded.
+* `manager.build.on_start(info)` - Triggers before the build process. E.g., before `dx build`.
+* `manager.build.on_finish(info)` - Triggers after the build process. E.g., after `dx build`.
+* `manager.serve.on_start(info)` - Triggers before the serving process. E.g., before `dx serve`.
+* `manager.serve.on_rebuild_start(info)` - Triggers before the server rebuilds the web with hot reload.
+* `manager.serve.on_rebuild_end(info)` - Triggers after the server rebuilds the web with hot reload.
+* `manager.serve.on_shutdown` - Triggers when the server is shutdown. E.g., when the `dx serve` process is terminated.
+
+To subscribe to an event, you simply need to assign it to a function:
+
+```lua
+manager.build.on_start = function (info)
+    log.info("[plugin] Build starting: " .. info.name)
+end
+```
+
+### Plugin template
 
 
 ```lua
 ```lua
 package.path = library_dir .. "/?.lua"
 package.path = library_dir .. "/?.lua"

+ 4 - 4
packages/cli/docs/src/plugin/interface/command.md

@@ -1,15 +1,15 @@
 # Command Functions
 # Command Functions
 
 
-> you can use command functions to execute some code & script
+You can use command functions to execute code and scripts.
 
 
-Type Define:
+Type definition:
 ```
 ```
 Stdio: "Inherit" | "Piped" | "Null"
 Stdio: "Inherit" | "Piped" | "Null"
 ```
 ```
 
 
 ### `exec(commands: [string], stdout: Stdio, stderr: Stdio)`
 ### `exec(commands: [string], stdout: Stdio, stderr: Stdio)`
 
 
-you can use this function to run some command on the current system.
+You can use this function to run some commands on the current system.
 
 
 ```lua
 ```lua
 local cmd = plugin.command
 local cmd = plugin.command
@@ -18,4 +18,4 @@ manager.test = function ()
     cmd.exec({"git", "clone", "https://github.com/DioxusLabs/cli-plugin-library"})
     cmd.exec({"git", "clone", "https://github.com/DioxusLabs/cli-plugin-library"})
 end
 end
 ```
 ```
-> Warning: This function don't have exception catch.
+> Warning: This function doesn't catch exceptions.

+ 7 - 12
packages/cli/docs/src/plugin/interface/dirs.md

@@ -1,33 +1,28 @@
 # Dirs Functions
 # Dirs Functions
 
 
-> you can use Dirs functions to get some directory path
+Dirs functions are for getting various directory paths. Not to be confused with `plugin.path`.
 
 
+### `plugin_dir() -> string`
 
 
-### plugin_dir() -> string
-
-You can get current plugin **root** directory path
+Get the plugin's root directory path.
 
 
 ```lua
 ```lua
 local path = plugin.dirs.plugin_dir()
 local path = plugin.dirs.plugin_dir()
 -- example: ~/Development/DioxusCli/plugin/test-plugin/
 -- example: ~/Development/DioxusCli/plugin/test-plugin/
 ```
 ```
 
 
-### bin_dir() -> string
-
-You can get plugin **bin** direcotry path
+### `bin_dir() -> string`
 
 
-Sometime you need install some binary file like `tailwind-cli` & `sass-cli` to help your plugin work, then you should put binary file in this directory.
+Get the plugin's binary directory path. Put binary files like `tailwind-cli` or `sass-cli` in this directory.
 
 
 ```lua
 ```lua
 local path = plugin.dirs.bin_dir()
 local path = plugin.dirs.bin_dir()
 -- example: ~/Development/DioxusCli/plugin/test-plugin/bin/
 -- example: ~/Development/DioxusCli/plugin/test-plugin/bin/
 ```
 ```
 
 
-### temp_dir() -> string
-
-You can get plugin **temp** direcotry path
+### `temp_dir() -> string`
 
 
-Just put some temporary file in this directory.
+Get the plugin's temporary directory path. Put any temporary files here.
 
 
 ```lua
 ```lua
 local path = plugin.dirs.bin_dir()
 local path = plugin.dirs.bin_dir()

+ 11 - 11
packages/cli/docs/src/plugin/interface/log.md

@@ -1,46 +1,46 @@
 # Log Functions
 # Log Functions
 
 
-> You can use log function to print some useful log info
+You can use log functions to print various logging information.
 
 
-### Trace(info: string)
+### `trace(info: string)`
 
 
-Print trace log info
+Print trace log info.
 
 
 ```lua
 ```lua
 local log = plugin.log
 local log = plugin.log
 log.trace("trace information")
 log.trace("trace information")
 ```
 ```
 
 
-### Debug(info: string)
+### `debug(info: string)`
 
 
-Print debug log info
+Print debug log info.
 
 
 ```lua
 ```lua
 local log = plugin.log
 local log = plugin.log
 log.debug("debug information")
 log.debug("debug information")
 ```
 ```
 
 
-### Info(info: string)
+### `info(info: string)`
 
 
-Print info log info
+Print info log info.
 
 
 ```lua
 ```lua
 local log = plugin.log
 local log = plugin.log
 log.info("info information")
 log.info("info information")
 ```
 ```
 
 
-### Warn(info: string)
+### `warn(info: string)`
 
 
-Print warning log info
+Print warning log info.
 
 
 ```lua
 ```lua
 local log = plugin.log
 local log = plugin.log
 log.warn("warn information")
 log.warn("warn information")
 ```
 ```
 
 
-### Error(info: string)
+### `error(info: string)`
 
 
-Print error log info
+Print error log info.
 
 
 ```lua
 ```lua
 local log = plugin.log
 local log = plugin.log

+ 9 - 6
packages/cli/docs/src/plugin/interface/network.md

@@ -1,12 +1,13 @@
 # Network Functions
 # Network Functions
 
 
-> you can use Network functions to download & read some data from internet
+You can use Network functions to download & read some data from the internet.
 
 
-### download_file(url: string, path: string) -> boolean
+### `download_file(url: string, path: string) -> boolean`
 
 
-This function can help you download some file from url, and it will return a *boolean* value to check the download status. (true: success | false: fail)
+Downloads a file from the specified URL,
+and returns a `boolean` that represents the download status (true: success, false: failure).
 
 
-You need pass a target url and a local path (where you want to save this file)
+You need to pass a target URL and a local path (where you want to save this file).
 
 
 ```lua
 ```lua
 -- this file will download to plugin temp directory
 -- this file will download to plugin temp directory
@@ -19,9 +20,11 @@ if status != true then
 end
 end
 ```
 ```
 
 
-### clone_repo(url: string, path: string) -> boolean
+### `clone_repo(url: string, path: string) -> boolean`
 
 
-This function can help you use `git clone` command (this system must have been installed git)
+Clone a repository from the given URL into the given path.
+Returns a `boolean` that represents the clone status (true: success, false: failure).
+The system executing this function must have git installed.
 
 
 ```lua
 ```lua
 local status = plugin.network.clone_repo(
 local status = plugin.network.clone_repo(

+ 3 - 3
packages/cli/docs/src/plugin/interface/os.md

@@ -1,10 +1,10 @@
 # OS Functions
 # OS Functions
 
 
-> you can use OS functions to get some system information
+OS functions are for getting system information.
 
 
-### current_platform() -> string ("windows" | "macos" | "linux")
+### `current_platform() -> string ("windows" | "macos" | "linux")`
 
 
-This function can help you get system & platform type:
+Get the current OS platform.
 
 
 ```lua
 ```lua
 local platform = plugin.os.current_platform()
 local platform = plugin.os.current_platform()

+ 14 - 11
packages/cli/docs/src/plugin/interface/path.md

@@ -1,10 +1,13 @@
 # Path Functions
 # Path Functions
 
 
-> you can use path functions to operate valid path string
+You can use path functions to perform operations on valid path strings.
 
 
-### join(path: string, extra: string) -> string
+### `join(path: string, extra: string) -> string`
 
 
-This function can help you extend a path, you can extend any path, dirname or filename.
+<!-- TODO: Add specifics.
+From the example given, it seems like it just creates a subdirectory path.
+What would it do when "extending" file paths? -->
+Extend a path; you can extend both directory and file paths.
 
 
 ```lua
 ```lua
 local current_path = "~/hello/dioxus"
 local current_path = "~/hello/dioxus"
@@ -12,9 +15,9 @@ local new_path = plugin.path.join(current_path, "world")
 -- new_path = "~/hello/dioxus/world"
 -- new_path = "~/hello/dioxus/world"
 ```
 ```
 
 
-### parent(path: string) -> string
+### `parent(path: string) -> string`
 
 
-This function will return `path` parent-path string, back to the parent.
+Return the parent path of the specified path. The parent path is always a directory.
 
 
 ```lua
 ```lua
 local current_path = "~/hello/dioxus"
 local current_path = "~/hello/dioxus"
@@ -22,14 +25,14 @@ local new_path = plugin.path.parent(current_path)
 -- new_path = "~/hello/"
 -- new_path = "~/hello/"
 ```
 ```
 
 
-### exists(path: string) -> boolean
+### `exists(path: string) -> boolean`
 
 
-This function can check some path (dir & file) is exists.
+Check if the specified path exists, as either a file or a directory.
 
 
-### is_file(path: string) -> boolean
+### `is_file(path: string) -> boolean`
 
 
-This function can check some path is a exist file.
+Check if the specified path is a file.
 
 
-### is_dir(path: string) -> boolean
+### `is_dir(path: string) -> boolean`
 
 
-This function can check some path is a exist dir.
+Check if the specified path is a directory.

+ 5 - 6
packages/cli/src/builder.rs

@@ -22,6 +22,7 @@ pub struct BuildResult {
     pub elapsed_time: u128,
     pub elapsed_time: u128,
 }
 }
 
 
+#[allow(unused)]
 pub fn build(config: &CrateConfig, quiet: bool) -> Result<BuildResult> {
 pub fn build(config: &CrateConfig, quiet: bool) -> Result<BuildResult> {
     // [1] Build the project with cargo, generating a wasm32-unknown-unknown target (is there a more specific, better target to leverage?)
     // [1] Build the project with cargo, generating a wasm32-unknown-unknown target (is there a more specific, better target to leverage?)
     // [2] Generate the appropriate build folders
     // [2] Generate the appropriate build folders
@@ -53,7 +54,8 @@ pub fn build(config: &CrateConfig, quiet: bool) -> Result<BuildResult> {
         .arg("build")
         .arg("build")
         .arg("--target")
         .arg("--target")
         .arg("wasm32-unknown-unknown")
         .arg("wasm32-unknown-unknown")
-        .arg("--message-format=json");
+        .arg("--message-format=json")
+        .arg("--quiet");
 
 
     let cmd = if config.release {
     let cmd = if config.release {
         cmd.arg("--release")
         cmd.arg("--release")
@@ -66,8 +68,6 @@ pub fn build(config: &CrateConfig, quiet: bool) -> Result<BuildResult> {
         cmd
         cmd
     };
     };
 
 
-    let cmd = if quiet { cmd.arg("--quiet") } else { cmd };
-
     let cmd = if config.custom_profile.is_some() {
     let cmd = if config.custom_profile.is_some() {
         let custom_profile = config.custom_profile.as_ref().unwrap();
         let custom_profile = config.custom_profile.as_ref().unwrap();
         cmd.arg("--profile").arg(custom_profile)
         cmd.arg("--profile").arg(custom_profile)
@@ -386,10 +386,9 @@ fn prettier_build(cmd: subprocess::Exec) -> anyhow::Result<Vec<Diagnostic>> {
         }
         }
     }
     }
 
 
-    StopSpinOnDrop(pb.clone());
-
     let stdout = cmd.detached().stream_stdout()?;
     let stdout = cmd.detached().stream_stdout()?;
     let reader = std::io::BufReader::new(stdout);
     let reader = std::io::BufReader::new(stdout);
+
     for message in cargo_metadata::Message::parse_stream(reader) {
     for message in cargo_metadata::Message::parse_stream(reader) {
         match message.unwrap() {
         match message.unwrap() {
             Message::CompilerMessage(msg) => {
             Message::CompilerMessage(msg) => {
@@ -409,7 +408,7 @@ fn prettier_build(cmd: subprocess::Exec) -> anyhow::Result<Vec<Diagnostic>> {
                 }
                 }
             }
             }
             Message::CompilerArtifact(artifact) => {
             Message::CompilerArtifact(artifact) => {
-                pb.set_message(format!("Compiling {} ", artifact.package_id));
+                pb.set_message(format!("⚙️ Compiling {} ", artifact.package_id));
                 pb.tick();
                 pb.tick();
             }
             }
             Message::BuildScriptExecuted(script) => {
             Message::BuildScriptExecuted(script) => {

+ 1 - 1
packages/cli/src/cli/build.rs

@@ -42,7 +42,7 @@ impl Build {
 
 
         match platform {
         match platform {
             Platform::Web => {
             Platform::Web => {
-                crate::builder::build(&crate_config, false)?;
+                crate::builder::build(&crate_config, true)?;
             }
             }
             Platform::Desktop => {
             Platform::Desktop => {
                 crate::builder::build_desktop(&crate_config, false)?;
                 crate::builder::build_desktop(&crate_config, false)?;

+ 1 - 1
packages/cli/src/lib.rs

@@ -1,4 +1,4 @@
-pub const DIOXUS_CLI_VERSION: &str = "0.1.5";
+pub const DIOXUS_CLI_VERSION: &str = "0.4.1";
 
 
 pub mod builder;
 pub mod builder;
 pub mod server;
 pub mod server;

+ 2 - 2
packages/cli/src/server/web/mod.rs

@@ -73,7 +73,7 @@ pub async fn serve_default(
     config: CrateConfig,
     config: CrateConfig,
     start_browser: bool,
     start_browser: bool,
 ) -> Result<()> {
 ) -> Result<()> {
-    let first_build_result = crate::builder::build(&config, false)?;
+    let first_build_result = crate::builder::build(&config, true)?;
 
 
     log::info!("🚀 Starting development server...");
     log::info!("🚀 Starting development server...");
 
 
@@ -134,7 +134,7 @@ pub async fn serve_hot_reload(
     config: CrateConfig,
     config: CrateConfig,
     start_browser: bool,
     start_browser: bool,
 ) -> Result<()> {
 ) -> Result<()> {
-    let first_build_result = crate::builder::build(&config, false)?;
+    let first_build_result = crate::builder::build(&config, true)?;
 
 
     log::info!("🚀 Starting development server...");
     log::info!("🚀 Starting development server...");
 
 

+ 1 - 1
packages/core/Cargo.toml

@@ -28,7 +28,7 @@ slab = { workspace = true }
 futures-channel = { workspace = true }
 futures-channel = { workspace = true }
 
 
 smallbox = "0.8.1"
 smallbox = "0.8.1"
-log = { workspace = true }
+tracing = { workspace = true }
 
 
 # Serialize the Edits for use in Webview/Liveview instances
 # Serialize the Edits for use in Webview/Liveview instances
 serde = { version = "1", features = ["derive"], optional = true }
 serde = { version = "1", features = ["derive"], optional = true }

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

@@ -68,7 +68,7 @@ unsafe impl<'a, P> AnyProps<'a> for VProps<'a, P> {
             Ok(None) => RenderReturn::default(),
             Ok(None) => RenderReturn::default(),
             Err(err) => {
             Err(err) => {
                 let component_name = cx.name();
                 let component_name = cx.name();
-                log::error!("Error while rendering component `{component_name}`: {err:?}");
+                tracing::error!("Error while rendering component `{component_name}`: {err:?}");
                 RenderReturn::default()
                 RenderReturn::default()
             }
             }
         }
         }

+ 7 - 1
packages/core/src/diff.rs

@@ -196,7 +196,8 @@ impl<'b> VirtualDom {
         right.scope.set(Some(scope_id));
         right.scope.set(Some(scope_id));
 
 
         // copy out the box for both
         // copy out the box for both
-        let old = self.scopes[scope_id.0].props.as_ref();
+        let old_scope = &self.scopes[scope_id.0];
+        let old = old_scope.props.as_ref();
         let new: Box<dyn AnyProps> = right.props.take().unwrap();
         let new: Box<dyn AnyProps> = right.props.take().unwrap();
         let new: Box<dyn AnyProps> = unsafe { std::mem::transmute(new) };
         let new: Box<dyn AnyProps> = unsafe { std::mem::transmute(new) };
 
 
@@ -204,6 +205,11 @@ impl<'b> VirtualDom {
         // The target scopestate still has the reference to the old props, so there's no need to update anything
         // The target scopestate still has the reference to the old props, so there's no need to update anything
         // This also implicitly drops the new props since they're not used
         // This also implicitly drops the new props since they're not used
         if left.static_props && unsafe { old.as_ref().unwrap().memoize(new.as_ref()) } {
         if left.static_props && unsafe { old.as_ref().unwrap().memoize(new.as_ref()) } {
+            tracing::trace!(
+                "Memoized props for component {:#?} ({})",
+                scope_id,
+                old_scope.context().name
+            );
             return;
             return;
         }
         }
 
 

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

@@ -118,7 +118,7 @@ impl<T: std::fmt::Debug> std::fmt::Debug for Event<T> {
 ///
 ///
 /// ```rust, ignore
 /// ```rust, ignore
 /// rsx!{
 /// rsx!{
-///     MyComponent { onclick: move |evt| log::info!("clicked") }
+///     MyComponent { onclick: move |evt| tracing::debug!("clicked") }
 /// }
 /// }
 ///
 ///
 /// #[derive(Props)]
 /// #[derive(Props)]

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

@@ -691,7 +691,7 @@ impl<'a> IntoDynNode<'a> for &Element<'a> {
 
 
 impl<'a, 'b> IntoDynNode<'a> for LazyNodes<'a, 'b> {
 impl<'a, 'b> IntoDynNode<'a> for LazyNodes<'a, 'b> {
     fn into_vnode(self, cx: &'a ScopeState) -> DynamicNode<'a> {
     fn into_vnode(self, cx: &'a ScopeState) -> DynamicNode<'a> {
-        DynamicNode::Fragment(cx.bump().alloc([self.call(cx)]))
+        DynamicNode::Fragment(cx.bump().alloc([cx.render(self).unwrap()]))
     }
     }
 }
 }
 
 
@@ -750,7 +750,7 @@ impl<'a> IntoTemplate<'a> for Element<'a> {
 }
 }
 impl<'a, 'b> IntoTemplate<'a> for LazyNodes<'a, 'b> {
 impl<'a, 'b> IntoTemplate<'a> for LazyNodes<'a, 'b> {
     fn into_template(self, cx: &'a ScopeState) -> VNode<'a> {
     fn into_template(self, cx: &'a ScopeState) -> VNode<'a> {
-        self.call(cx)
+        cx.render(self).unwrap()
     }
     }
 }
 }
 
 

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

@@ -64,6 +64,7 @@ impl VirtualDom {
             let props: &dyn AnyProps = scope.props.as_ref().unwrap().as_ref();
             let props: &dyn AnyProps = scope.props.as_ref().unwrap().as_ref();
             let props: &dyn AnyProps = std::mem::transmute(props);
             let props: &dyn AnyProps = std::mem::transmute(props);
 
 
+            let _span = tracing::trace_span!("render", scope = %scope.context().name);
             props.render(scope).extend_lifetime()
             props.render(scope).extend_lifetime()
         };
         };
 
 

+ 34 - 7
packages/core/src/scope_context.rs

@@ -107,20 +107,30 @@ impl ScopeContext {
     ///
     ///
     /// Clones the state if it exists.
     /// Clones the state if it exists.
     pub fn consume_context<T: 'static + Clone>(&self) -> Option<T> {
     pub fn consume_context<T: 'static + Clone>(&self) -> Option<T> {
+        tracing::trace!(
+            "looking for context {} ({:?}) in {}",
+            std::any::type_name::<T>(),
+            std::any::TypeId::of::<T>(),
+            self.name
+        );
         if let Some(this_ctx) = self.has_context() {
         if let Some(this_ctx) = self.has_context() {
             return Some(this_ctx);
             return Some(this_ctx);
         }
         }
 
 
         let mut search_parent = self.parent_id;
         let mut search_parent = self.parent_id;
-        with_runtime(|runtime| {
+        match with_runtime(|runtime: &crate::runtime::Runtime| {
             while let Some(parent_id) = search_parent {
             while let Some(parent_id) = search_parent {
                 let parent = runtime.get_context(parent_id).unwrap();
                 let parent = runtime.get_context(parent_id).unwrap();
-                if let Some(shared) = parent
-                    .shared_contexts
-                    .borrow()
-                    .iter()
-                    .find_map(|any| any.downcast_ref::<T>())
-                {
+                tracing::trace!(
+                    "looking for context {} ({:?}) in {}",
+                    std::any::type_name::<T>(),
+                    std::any::TypeId::of::<T>(),
+                    parent.name
+                );
+                if let Some(shared) = parent.shared_contexts.borrow().iter().find_map(|any| {
+                    tracing::trace!("found context {:?}", any.type_id());
+                    any.downcast_ref::<T>()
+                }) {
                     return Some(shared.clone());
                     return Some(shared.clone());
                 }
                 }
                 search_parent = parent.parent_id;
                 search_parent = parent.parent_id;
@@ -128,6 +138,17 @@ impl ScopeContext {
             None
             None
         })
         })
         .flatten()
         .flatten()
+        {
+            Some(ctx) => Some(ctx),
+            None => {
+                tracing::trace!(
+                    "context {} ({:?}) not found",
+                    std::any::type_name::<T>(),
+                    std::any::TypeId::of::<T>()
+                );
+                None
+            }
+        }
     }
     }
 
 
     /// Expose state to children further down the [`crate::VirtualDom`] Tree. Requires `Clone` on the context to allow getting values down the tree.
     /// Expose state to children further down the [`crate::VirtualDom`] Tree. Requires `Clone` on the context to allow getting values down the tree.
@@ -152,6 +173,12 @@ impl ScopeContext {
     /// }
     /// }
     /// ```
     /// ```
     pub fn provide_context<T: 'static + Clone>(&self, value: T) -> T {
     pub fn provide_context<T: 'static + Clone>(&self, value: T) -> T {
+        tracing::trace!(
+            "providing context {} ({:?}) in {}",
+            std::any::type_name::<T>(),
+            std::any::TypeId::of::<T>(),
+            self.name
+        );
         let mut contexts = self.shared_contexts.borrow_mut();
         let mut contexts = self.shared_contexts.borrow_mut();
 
 
         // If the context exists, swap it out for the new value
         // If the context exists, swap it out for the new value

+ 2 - 1
packages/core/src/virtual_dom.rs

@@ -306,6 +306,7 @@ impl VirtualDom {
     pub fn mark_dirty(&mut self, id: ScopeId) {
     pub fn mark_dirty(&mut self, id: ScopeId) {
         if let Some(scope) = self.get_scope(id) {
         if let Some(scope) = self.get_scope(id) {
             let height = scope.height();
             let height = scope.height();
+            tracing::trace!("Marking scope {:?} ({}) as dirty", id, scope.context().name);
             self.dirty_scopes.insert(DirtyScope { height, id });
             self.dirty_scopes.insert(DirtyScope { height, id });
         }
         }
     }
     }
@@ -558,7 +559,7 @@ impl VirtualDom {
             }
             }
             // If an error occurs, we should try to render the default error component and context where the error occured
             // If an error occurs, we should try to render the default error component and context where the error occured
             RenderReturn::Aborted(placeholder) => {
             RenderReturn::Aborted(placeholder) => {
-                log::info!("Ran into suspended or aborted scope during rebuild");
+                tracing::debug!("Ran into suspended or aborted scope during rebuild");
                 let id = self.next_null();
                 let id = self.next_null();
                 placeholder.id.set(Some(id));
                 placeholder.id.set(Some(id));
                 self.mutations.push(Mutation::CreatePlaceholder { id });
                 self.mutations.push(Mutation::CreatePlaceholder { id });

+ 3 - 1
packages/desktop/Cargo.toml

@@ -18,7 +18,7 @@ dioxus-hot-reload = { workspace = true, optional = true }
 serde = "1.0.136"
 serde = "1.0.136"
 serde_json = "1.0.79"
 serde_json = "1.0.79"
 thiserror = { workspace = true }
 thiserror = { workspace = true }
-log = { workspace = true }
+tracing = { workspace = true }
 wry = { version = "0.31.0" }
 wry = { version = "0.31.0" }
 futures-channel = { workspace = true }
 futures-channel = { workspace = true }
 tokio = { workspace = true, features = [
 tokio = { workspace = true, features = [
@@ -57,6 +57,8 @@ default = ["tokio_runtime", "hot-reload"]
 tokio_runtime = ["tokio"]
 tokio_runtime = ["tokio"]
 fullscreen = ["wry/fullscreen"]
 fullscreen = ["wry/fullscreen"]
 transparent = ["wry/transparent"]
 transparent = ["wry/transparent"]
+devtools = ["wry/devtools"]
+dox = ["wry/dox"]
 hot-reload = ["dioxus-hot-reload"]
 hot-reload = ["dioxus-hot-reload"]
 
 
 [dev-dependencies]
 [dev-dependencies]

+ 2 - 2
packages/desktop/src/desktop_context.rs

@@ -191,7 +191,7 @@ impl DesktopService {
     /// launch print modal
     /// launch print modal
     pub fn print(&self) {
     pub fn print(&self) {
         if let Err(e) = self.webview.print() {
         if let Err(e) = self.webview.print() {
-            log::warn!("Open print modal failed: {e}");
+            tracing::warn!("Open print modal failed: {e}");
         }
         }
     }
     }
 
 
@@ -206,7 +206,7 @@ impl DesktopService {
         self.webview.open_devtools();
         self.webview.open_devtools();
 
 
         #[cfg(not(debug_assertions))]
         #[cfg(not(debug_assertions))]
-        log::warn!("Devtools are disabled in release builds");
+        tracing::warn!("Devtools are disabled in release builds");
     }
     }
 
 
     /// Create a wry event handler that listens for wry events.
     /// Create a wry event handler that listens for wry events.

+ 1 - 1
packages/desktop/src/lib.rs

@@ -336,7 +336,7 @@ pub fn launch_with_props<P: 'static>(root: Component<P>, props: P, cfg: Config)
                         if temp.contains_key("href") {
                         if temp.contains_key("href") {
                             let open = webbrowser::open(temp["href"].as_str().unwrap());
                             let open = webbrowser::open(temp["href"].as_str().unwrap());
                             if let Err(e) = open {
                             if let Err(e) = open {
-                                log::error!("Open Browser error: {:?}", e);
+                                tracing::error!("Open Browser error: {:?}", e);
                             }
                             }
                         }
                         }
                     }
                     }

+ 1 - 1
packages/desktop/src/query.rs

@@ -123,7 +123,7 @@ impl QueryEngine {
                 }})
                 }})
             }})();"#
             }})();"#
         )) {
         )) {
-            log::warn!("Query error: {err}");
+            tracing::warn!("Query error: {err}");
         }
         }
 
 
         Query {
         Query {

+ 1 - 1
packages/dioxus/Cargo.toml

@@ -30,7 +30,7 @@ hot-reload = ["dioxus-hot-reload"]
 
 
 [dev-dependencies]
 [dev-dependencies]
 futures-util = { workspace = true }
 futures-util = { workspace = true }
-log = { workspace = true }
+tracing = { workspace = true }
 rand = { version = "0.8.4", features = ["small_rng"] }
 rand = { version = "0.8.4", features = ["small_rng"] }
 criterion = "0.3.5"
 criterion = "0.3.5"
 thiserror = { workspace = true }
 thiserror = { workspace = true }

+ 1 - 1
packages/fermi/Cargo.toml

@@ -14,7 +14,7 @@ keywords = ["dom", "ui", "gui", "react", "state-management"]
 [dependencies]
 [dependencies]
 dioxus-core = { workspace = true }
 dioxus-core = { workspace = true }
 im-rc = { version = "15.0.0", features = ["serde"] }
 im-rc = { version = "15.0.0", features = ["serde"] }
-log = { workspace = true }
+tracing = { workspace = true }
 
 
 [dev-dependencies]
 [dev-dependencies]
 closure = "0.3.0"
 closure = "0.3.0"

+ 4 - 4
packages/fermi/src/root.rs

@@ -66,14 +66,14 @@ impl AtomRoot {
 
 
         if let Some(slot) = atoms.get_mut(&ptr) {
         if let Some(slot) = atoms.get_mut(&ptr) {
             slot.value = Rc::new(value);
             slot.value = Rc::new(value);
-            log::trace!("found item with subscribers {:?}", slot.subscribers);
+            tracing::trace!("found item with subscribers {:?}", slot.subscribers);
 
 
             for scope in &slot.subscribers {
             for scope in &slot.subscribers {
-                log::trace!("updating subcsriber");
+                tracing::trace!("updating subcsriber");
                 (self.update_any)(*scope);
                 (self.update_any)(*scope);
             }
             }
         } else {
         } else {
-            log::trace!("no atoms found for {:?}", ptr);
+            tracing::trace!("no atoms found for {:?}", ptr);
             atoms.insert(
             atoms.insert(
                 ptr,
                 ptr,
                 Slot {
                 Slot {
@@ -96,7 +96,7 @@ impl AtomRoot {
     pub fn force_update(&self, ptr: AtomId) {
     pub fn force_update(&self, ptr: AtomId) {
         if let Some(slot) = self.atoms.borrow_mut().get(&ptr) {
         if let Some(slot) = self.atoms.borrow_mut().get(&ptr) {
             for scope in slot.subscribers.iter() {
             for scope in slot.subscribers.iter() {
-                log::trace!("updating subcsriber");
+                tracing::trace!("updating subcsriber");
                 (self.update_any)(*scope);
                 (self.update_any)(*scope);
             }
             }
         }
         }

+ 2 - 1
packages/fullstack/Cargo.toml

@@ -44,7 +44,8 @@ dioxus-desktop = { workspace = true, optional = true }
 # Router Integration
 # Router Integration
 dioxus-router = { workspace = true, optional = true }
 dioxus-router = { workspace = true, optional = true }
 
 
-log = { workspace = true }
+tracing = { workspace = true }
+tracing-futures = { workspace = true }
 once_cell = "1.17.1"
 once_cell = "1.17.1"
 thiserror = { workspace = true }
 thiserror = { workspace = true }
 tokio = { workspace = true, features = ["full"], optional = true }
 tokio = { workspace = true, features = ["full"], optional = true }

+ 3 - 2
packages/fullstack/examples/axum-hello-world/Cargo.toml

@@ -12,8 +12,9 @@ dioxus-fullstack = { workspace = true }
 axum = { version = "0.6.12", optional = true }
 axum = { version = "0.6.12", optional = true }
 serde = "1.0.159"
 serde = "1.0.159"
 simple_logger = "4.2.0"
 simple_logger = "4.2.0"
-wasm-logger = "0.2.0"
-log.workspace = true
+tracing-wasm = "0.2.1"
+tracing.workspace = true
+tracing-subscriber = "0.3.17"
 reqwest = "0.11.18"
 reqwest = "0.11.18"
 
 
 [features]
 [features]

+ 2 - 3
packages/fullstack/examples/axum-hello-world/src/main.rs

@@ -12,7 +12,6 @@ use dioxus_fullstack::{
     prelude::*,
     prelude::*,
 };
 };
 use serde::{Deserialize, Serialize};
 use serde::{Deserialize, Serialize};
-use wasm_logger::Config;
 
 
 #[derive(Props, PartialEq, Debug, Default, Serialize, Deserialize, Clone)]
 #[derive(Props, PartialEq, Debug, Default, Serialize, Deserialize, Clone)]
 struct AppProps {
 struct AppProps {
@@ -66,9 +65,9 @@ async fn get_server_data() -> Result<String, ServerFnError> {
 
 
 fn main() {
 fn main() {
     #[cfg(feature = "web")]
     #[cfg(feature = "web")]
-    wasm_logger::init(wasm_logger::Config::new(log::Level::Trace));
+    tracing_wasm::set_as_global_default();
     #[cfg(feature = "ssr")]
     #[cfg(feature = "ssr")]
-    simple_logger::SimpleLogger::new().init().unwrap();
+    tracing_subscriber::fmt::init();
 
 
     LaunchBuilder::new_with_props(app, AppProps { count: 0 }).launch()
     LaunchBuilder::new_with_props(app, AppProps { count: 0 }).launch()
 }
 }

+ 3 - 2
packages/fullstack/examples/salvo-hello-world/Cargo.toml

@@ -16,8 +16,9 @@ salvo = { version = "0.37.9", optional = true }
 execute = "0.2.12"
 execute = "0.2.12"
 reqwest = "0.11.18"
 reqwest = "0.11.18"
 simple_logger = "4.2.0"
 simple_logger = "4.2.0"
-log.workspace = true
-wasm-logger = "0.2.0"
+tracing-wasm = "0.2.1"
+tracing.workspace = true
+tracing-subscriber = "0.3.17"
 
 
 [features]
 [features]
 default = []
 default = []

+ 2 - 2
packages/fullstack/examples/salvo-hello-world/src/main.rs

@@ -60,9 +60,9 @@ async fn get_server_data() -> Result<String, ServerFnError> {
 
 
 fn main() {
 fn main() {
     #[cfg(feature = "web")]
     #[cfg(feature = "web")]
-    wasm_logger::init(wasm_logger::Config::new(log::Level::Trace));
+    tracing_wasm::set_as_global_default();
     #[cfg(feature = "ssr")]
     #[cfg(feature = "ssr")]
-    simple_logger::SimpleLogger::new().init().unwrap();
+    tracing_subscriber::fmt::init();
 
 
     LaunchBuilder::new_with_props(app, AppProps { count: 0 }).launch()
     LaunchBuilder::new_with_props(app, AppProps { count: 0 }).launch()
 }
 }

+ 3 - 2
packages/fullstack/examples/warp-hello-world/Cargo.toml

@@ -16,8 +16,9 @@ warp = { version = "0.3.3", optional = true }
 execute = "0.2.12"
 execute = "0.2.12"
 reqwest = "0.11.18"
 reqwest = "0.11.18"
 simple_logger = "4.2.0"
 simple_logger = "4.2.0"
-log.workspace = true
-wasm-logger = "0.2.0"
+tracing-wasm = "0.2.1"
+tracing.workspace = true
+tracing-subscriber = "0.3.17"
 
 
 [features]
 [features]
 default = []
 default = []

+ 2 - 2
packages/fullstack/examples/warp-hello-world/src/main.rs

@@ -60,9 +60,9 @@ async fn get_server_data() -> Result<String, ServerFnError> {
 
 
 fn main() {
 fn main() {
     #[cfg(feature = "web")]
     #[cfg(feature = "web")]
-    wasm_logger::init(wasm_logger::Config::new(log::Level::Trace));
+    tracing_wasm::set_as_global_default();
     #[cfg(feature = "ssr")]
     #[cfg(feature = "ssr")]
-    simple_logger::SimpleLogger::new().init().unwrap();
+    tracing_subscriber::fmt::init();
 
 
     LaunchBuilder::new_with_props(app, AppProps { count: 0 }).launch()
     LaunchBuilder::new_with_props(app, AppProps { count: 0 }).launch()
 }
 }

+ 1 - 1
packages/fullstack/src/adapters/axum_adapter.rs

@@ -389,7 +389,7 @@ pub async fn render_handler<P: Clone + serde::Serialize + Send + Sync + 'static>
             response
             response
         }
         }
         Err(e) => {
         Err(e) => {
-            log::error!("Failed to render page: {}", e);
+            tracing::error!("Failed to render page: {}", e);
             report_err(e).into_response()
             report_err(e).into_response()
         }
         }
     }
     }

+ 1 - 1
packages/fullstack/src/adapters/salvo_adapter.rs

@@ -423,7 +423,7 @@ impl<P: Clone + serde::Serialize + Send + Sync + 'static> Handler for SSRHandler
                 freshness.write(res.headers_mut());
                 freshness.write(res.headers_mut());
             }
             }
             Err(err) => {
             Err(err) => {
-                log::error!("Error rendering SSR: {}", err);
+                tracing::error!("Error rendering SSR: {}", err);
                 res.write_body("Error rendering SSR").unwrap();
                 res.write_body("Error rendering SSR").unwrap();
             }
             }
         };
         };

+ 3 - 3
packages/fullstack/src/adapters/warp_adapter.rs

@@ -84,7 +84,7 @@ use warp::{
 ///             async move {
 ///             async move {
 ///                 let req = warp::hyper::Request::from_parts(parts, bytes.into());
 ///                 let req = warp::hyper::Request::from_parts(parts, bytes.into());
 ///                 service.run(req).await.map_err(|err| {
 ///                 service.run(req).await.map_err(|err| {
-///                     log::error!("Server function error: {}", err);
+///                     tracing::error!("Server function error: {}", err);
 ///                     warp::reject::reject()
 ///                     warp::reject::reject()
 ///                 })
 ///                 })
 ///             }
 ///             }
@@ -142,7 +142,7 @@ pub fn register_server_fns(server_fn_route: &'static str) -> BoxedFilter<(impl R
                 async move {
                 async move {
                     let req = warp::hyper::Request::from_parts(parts, bytes.into());
                     let req = warp::hyper::Request::from_parts(parts, bytes.into());
                     service.run(req).await.map_err(|err| {
                     service.run(req).await.map_err(|err| {
-                        log::error!("Server function error: {}", err);
+                        tracing::error!("Server function error: {}", err);
                         warp::reject::reject()
                         warp::reject::reject()
                     })
                     })
                 }
                 }
@@ -222,7 +222,7 @@ pub fn render_ssr<P: Clone + serde::Serialize + Send + Sync + 'static>(
                         res
                         res
                     }
                     }
                     Err(err) => {
                     Err(err) => {
-                        log::error!("Failed to render ssr: {}", err);
+                        tracing::error!("Failed to render ssr: {}", err);
                         Response::builder()
                         Response::builder()
                             .status(500)
                             .status(500)
                             .body("Failed to render ssr".into())
                             .body("Failed to render ssr".into())

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

@@ -23,7 +23,7 @@ pub fn server_cached<O: 'static + Serialize + DeserializeOwned>(server_fn: impl
         let data = server_fn();
         let data = server_fn();
         let sc = crate::prelude::server_context();
         let sc = crate::prelude::server_context();
         if let Err(err) = sc.push_html_data(&data) {
         if let Err(err) = sc.push_html_data(&data) {
-            log::error!("Failed to push HTML data: {}", err);
+            tracing::error!("Failed to push HTML data: {}", err);
         }
         }
         data
         data
     }
     }

+ 4 - 4
packages/fullstack/src/hooks/server_future.rs

@@ -47,13 +47,13 @@ where
         if first_run {
         if first_run {
             match crate::html_storage::deserialize::take_server_data() {
             match crate::html_storage::deserialize::take_server_data() {
                 Some(data) => {
                 Some(data) => {
-                    log::trace!("Loaded {data:?} from server");
+                    tracing::trace!("Loaded {data:?} from server");
                     *state.value.borrow_mut() = Some(Box::new(data));
                     *state.value.borrow_mut() = Some(Box::new(data));
                     state.needs_regen.set(false);
                     state.needs_regen.set(false);
                     return Some(state);
                     return Some(state);
                 }
                 }
                 None => {
                 None => {
-                    log::trace!("Failed to load from server... running future");
+                    tracing::trace!("Failed to load from server... running future");
                 }
                 }
             };
             };
         }
         }
@@ -82,7 +82,7 @@ where
                 data = fut.await;
                 data = fut.await;
                 if first_run {
                 if first_run {
                     if let Err(err) = crate::prelude::server_context().push_html_data(&data) {
                     if let Err(err) = crate::prelude::server_context().push_html_data(&data) {
-                        log::error!("Failed to push HTML data: {}", err);
+                        tracing::error!("Failed to push HTML data: {}", err);
                     };
                     };
                 }
                 }
             }
             }
@@ -99,7 +99,7 @@ where
     if first_run {
     if first_run {
         #[cfg(feature = "ssr")]
         #[cfg(feature = "ssr")]
         {
         {
-            log::trace!("Suspending first run of use_server_future");
+            tracing::trace!("Suspending first run of use_server_future");
             cx.suspend();
             cx.suspend();
         }
         }
         None
         None

+ 1 - 1
packages/fullstack/src/hot_reload.rs

@@ -30,7 +30,7 @@ impl Default for HotReloadState {
                     }
                     }
 
 
                     if let Err(err) = tx.send(Some(template)) {
                     if let Err(err) = tx.send(Some(template)) {
-                        log::error!("Failed to send hot reload message: {}", err);
+                        tracing::error!("Failed to send hot reload message: {}", err);
                     }
                     }
                 }
                 }
                 dioxus_hot_reload::HotReloadMsg::Shutdown => {
                 dioxus_hot_reload::HotReloadMsg::Shutdown => {

+ 4 - 4
packages/fullstack/src/html_storage/deserialize.rs

@@ -10,7 +10,7 @@ pub(crate) fn serde_from_bytes<T: DeserializeOwned>(string: &[u8]) -> Option<T>
     let decompressed = match STANDARD.decode(string) {
     let decompressed = match STANDARD.decode(string) {
         Ok(bytes) => bytes,
         Ok(bytes) => bytes,
         Err(err) => {
         Err(err) => {
-            log::error!("Failed to decode base64: {}", err);
+            tracing::error!("Failed to decode base64: {}", err);
             return None;
             return None;
         }
         }
     };
     };
@@ -18,7 +18,7 @@ pub(crate) fn serde_from_bytes<T: DeserializeOwned>(string: &[u8]) -> Option<T>
     match postcard::from_bytes(&decompressed) {
     match postcard::from_bytes(&decompressed) {
         Ok(data) => Some(data),
         Ok(data) => Some(data),
         Err(err) => {
         Err(err) => {
-            log::error!("Failed to deserialize: {}", err);
+            tracing::error!("Failed to deserialize: {}", err);
             None
             None
         }
         }
     }
     }
@@ -32,14 +32,14 @@ static SERVER_DATA: once_cell::sync::Lazy<Option<HTMLDataCursor>> =
             let element = match window.get_element_by_id("dioxus-storage-data") {
             let element = match window.get_element_by_id("dioxus-storage-data") {
                 Some(element) => element,
                 Some(element) => element,
                 None => {
                 None => {
-                    log::error!("Failed to get element by id: dioxus-storage-data");
+                    tracing::error!("Failed to get element by id: dioxus-storage-data");
                     return None;
                     return None;
                 }
                 }
             };
             };
             let attribute = match element.get_attribute("data-serialized") {
             let attribute = match element.get_attribute("data-serialized") {
                 Some(attribute) => attribute,
                 Some(attribute) => attribute,
                 None => {
                 None => {
-                    log::error!("Failed to get attribute: data-serialized");
+                    tracing::error!("Failed to get attribute: data-serialized");
                     return None;
                     return None;
                 }
                 }
             };
             };

+ 2 - 2
packages/fullstack/src/html_storage/mod.rs

@@ -36,7 +36,7 @@ impl HTMLDataCursor {
     pub fn take<T: DeserializeOwned>(&self) -> Option<T> {
     pub fn take<T: DeserializeOwned>(&self) -> Option<T> {
         let current = self.index.load(std::sync::atomic::Ordering::SeqCst);
         let current = self.index.load(std::sync::atomic::Ordering::SeqCst);
         if current >= self.data.len() {
         if current >= self.data.len() {
-            log::error!(
+            tracing::error!(
                 "Tried to take more data than was available, len: {}, index: {}",
                 "Tried to take more data than was available, len: {}, index: {}",
                 self.data.len(),
                 self.data.len(),
                 current
                 current
@@ -48,7 +48,7 @@ impl HTMLDataCursor {
         match postcard::from_bytes(cursor) {
         match postcard::from_bytes(cursor) {
             Ok(x) => Some(x),
             Ok(x) => Some(x),
             Err(e) => {
             Err(e) => {
-                log::error!("Error deserializing data: {:?}", e);
+                tracing::error!("Error deserializing data: {:?}", e);
                 None
                 None
             }
             }
         }
         }

+ 6 - 1
packages/fullstack/src/layer.rs

@@ -1,4 +1,5 @@
 use std::pin::Pin;
 use std::pin::Pin;
+use tracing_futures::Instrument;
 
 
 use http::{Request, Response};
 use http::{Request, Response};
 
 
@@ -45,7 +46,11 @@ where
                 > + Send,
                 > + Send,
         >,
         >,
     > {
     > {
-        let fut = self.call(req);
+        let fut = self.call(req).instrument(tracing::trace_span!(
+            "service",
+            "{}",
+            std::any::type_name::<S>()
+        ));
         Box::pin(async move { fut.await.map_err(|err| err.into()) })
         Box::pin(async move { fut.await.map_err(|err| err.into()) })
     }
     }
 }
 }

+ 4 - 4
packages/fullstack/src/render.rs

@@ -50,10 +50,10 @@ impl SsrRendererPool {
                             let prev_context =
                             let prev_context =
                                 SERVER_CONTEXT.with(|ctx| ctx.replace(server_context));
                                 SERVER_CONTEXT.with(|ctx| ctx.replace(server_context));
                             // poll the future, which may call server_context()
                             // poll the future, which may call server_context()
-                            log::info!("Rebuilding vdom");
+                            tracing::info!("Rebuilding vdom");
                             let _ = vdom.rebuild();
                             let _ = vdom.rebuild();
                             vdom.wait_for_suspense().await;
                             vdom.wait_for_suspense().await;
-                            log::info!("Suspense resolved");
+                            tracing::info!("Suspense resolved");
                             // after polling the future, we need to restore the context
                             // after polling the future, we need to restore the context
                             SERVER_CONTEXT.with(|ctx| ctx.replace(prev_context));
                             SERVER_CONTEXT.with(|ctx| ctx.replace(prev_context));
 
 
@@ -116,10 +116,10 @@ impl SsrRendererPool {
                                             let prev_context = SERVER_CONTEXT
                                             let prev_context = SERVER_CONTEXT
                                                 .with(|ctx| ctx.replace(Box::new(server_context)));
                                                 .with(|ctx| ctx.replace(Box::new(server_context)));
                                             // poll the future, which may call server_context()
                                             // poll the future, which may call server_context()
-                                            log::info!("Rebuilding vdom");
+                                            tracing::info!("Rebuilding vdom");
                                             let _ = vdom.rebuild();
                                             let _ = vdom.rebuild();
                                             vdom.wait_for_suspense().await;
                                             vdom.wait_for_suspense().await;
-                                            log::info!("Suspense resolved");
+                                            tracing::info!("Suspense resolved");
                                             // after polling the future, we need to restore the context
                                             // after polling the future, we need to restore the context
                                             SERVER_CONTEXT.with(|ctx| ctx.replace(prev_context));
                                             SERVER_CONTEXT.with(|ctx| ctx.replace(prev_context));
                                         })
                                         })

+ 1 - 1
packages/fullstack/src/router.rs

@@ -29,7 +29,7 @@ where
                                 .to_string()
                                 .to_string()
                                 .parse()
                                 .parse()
                                 .unwrap_or_else(|err| {
                                 .unwrap_or_else(|err| {
-                                    log::error!("Failed to parse uri: {}", err);
+                                    tracing::error!("Failed to parse uri: {}", err);
                                     "/"
                                     "/"
                                         .parse()
                                         .parse()
                                         .unwrap_or_else(|err| {
                                         .unwrap_or_else(|err| {

+ 1 - 1
packages/hooks/Cargo.toml

@@ -16,7 +16,7 @@ nightly-features = []
 [dependencies]
 [dependencies]
 dioxus-core = { workspace = true }
 dioxus-core = { workspace = true }
 futures-channel = { workspace = true }
 futures-channel = { workspace = true }
-log = { workspace = true }
+tracing = { workspace = true }
 thiserror = { workspace = true }
 thiserror = { workspace = true }
 slab = { workspace = true }
 slab = { workspace = true }
 dioxus-debug-cell = "0.1.1"
 dioxus-debug-cell = "0.1.1"

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

@@ -1,4 +1,4 @@
-/// Creats a callback that will be run before the component is removed. This can be used to clean up side effects from the component (created with use_effect)
+/// Creates a callback that will be run before the component is removed. This can be used to clean up side effects from the component (created with use_effect)
 ///
 ///
 /// Example:
 /// Example:
 /// ```rust
 /// ```rust

+ 14 - 7
packages/hooks/src/use_shared_state.rs

@@ -81,10 +81,12 @@ pub(crate) struct ProvidedStateInner<T> {
     value: T,
     value: T,
     notify_any: Arc<dyn Fn(ScopeId)>,
     notify_any: Arc<dyn Fn(ScopeId)>,
     consumers: HashSet<ScopeId>,
     consumers: HashSet<ScopeId>,
+    gen: usize,
 }
 }
 
 
 impl<T> ProvidedStateInner<T> {
 impl<T> ProvidedStateInner<T> {
     pub(crate) fn notify_consumers(&mut self) {
     pub(crate) fn notify_consumers(&mut self) {
+        self.gen += 1;
         for consumer in self.consumers.iter() {
         for consumer in self.consumers.iter() {
             (self.notify_any)(*consumer);
             (self.notify_any)(*consumer);
         }
         }
@@ -157,7 +159,7 @@ impl<T> ProvidedStateInner<T> {
 ///
 ///
 /// Right now, there is not a distinction between read-only and write-only, so every consumer will be notified.
 /// Right now, there is not a distinction between read-only and write-only, so every consumer will be notified.
 pub fn use_shared_state<T: 'static>(cx: &ScopeState) -> Option<&UseSharedState<T>> {
 pub fn use_shared_state<T: 'static>(cx: &ScopeState) -> Option<&UseSharedState<T>> {
-    let state: &Option<UseSharedStateOwner<T>> = &*cx.use_hook(move || {
+    let state_owner: &mut Option<UseSharedStateOwner<T>> = &mut *cx.use_hook(move || {
         let scope_id = cx.scope_id();
         let scope_id = cx.scope_id();
         let root = cx.consume_context::<ProvidedState<T>>()?;
         let root = cx.consume_context::<ProvidedState<T>>()?;
 
 
@@ -167,7 +169,10 @@ pub fn use_shared_state<T: 'static>(cx: &ScopeState) -> Option<&UseSharedState<T
         let owner = UseSharedStateOwner { state, scope_id };
         let owner = UseSharedStateOwner { state, scope_id };
         Some(owner)
         Some(owner)
     });
     });
-    state.as_ref().map(|s| &s.state)
+    state_owner.as_mut().map(|s| {
+        s.state.gen = s.state.inner.borrow().gen;
+        &s.state
+    })
 }
 }
 
 
 /// This wrapper detects when the hook is dropped and will unsubscribe when the component is unmounted
 /// This wrapper detects when the hook is dropped and will unsubscribe when the component is unmounted
@@ -187,11 +192,13 @@ impl<T> Drop for UseSharedStateOwner<T> {
 /// State that is shared between components through the context system
 /// State that is shared between components through the context system
 pub struct UseSharedState<T> {
 pub struct UseSharedState<T> {
     pub(crate) inner: Rc<RefCell<ProvidedStateInner<T>>>,
     pub(crate) inner: Rc<RefCell<ProvidedStateInner<T>>>,
+    gen: usize,
 }
 }
 
 
 impl<T> UseSharedState<T> {
 impl<T> UseSharedState<T> {
     fn new(inner: Rc<RefCell<ProvidedStateInner<T>>>) -> Self {
     fn new(inner: Rc<RefCell<ProvidedStateInner<T>>>) -> Self {
-        Self { inner }
+        let gen = inner.borrow().gen;
+        Self { inner, gen }
     }
     }
 
 
     /// Notify all consumers of the state that it has changed. (This is called automatically when you call "write")
     /// Notify all consumers of the state that it has changed. (This is called automatically when you call "write")
@@ -302,15 +309,14 @@ impl<T> Clone for UseSharedState<T> {
     fn clone(&self) -> Self {
     fn clone(&self) -> Self {
         Self {
         Self {
             inner: self.inner.clone(),
             inner: self.inner.clone(),
+            gen: self.gen,
         }
         }
     }
     }
 }
 }
 
 
-impl<T: PartialEq> PartialEq for UseSharedState<T> {
+impl<T> PartialEq for UseSharedState<T> {
     fn eq(&self, other: &Self) -> bool {
     fn eq(&self, other: &Self) -> bool {
-        let first = self.inner.borrow();
-        let second = other.inner.borrow();
-        first.value == second.value
+        self.gen == other.gen
     }
     }
 }
 }
 
 
@@ -360,6 +366,7 @@ pub fn use_shared_state_provider<T: 'static>(cx: &ScopeState, f: impl FnOnce() -
             value: f(),
             value: f(),
             notify_any: cx.schedule_update_any(),
             notify_any: cx.schedule_update_any(),
             consumers: HashSet::new(),
             consumers: HashSet::new(),
+            gen: 0,
         }));
         }));
 
 
         cx.provide_context(state);
         cx.provide_context(state);

+ 2 - 0
packages/html/src/elements.rs

@@ -1258,6 +1258,8 @@ builder_constructors! {
         spellcheck: BoolOrDefault DEFAULT,
         spellcheck: BoolOrDefault DEFAULT,
         wrap: Wrap DEFAULT,
         wrap: Wrap DEFAULT,
         value: String volatile,
         value: String volatile,
+
+        initial_value: String DEFAULT,
     };
     };
 
 
 
 

+ 1 - 1
packages/html/src/events/mouse.rs

@@ -108,7 +108,7 @@ impl_event! {
     ///
     ///
     /// ## Example
     /// ## Example
     /// ```rust, ignore
     /// ```rust, ignore
-    /// rsx!( button { "click me", onclick: move |_| log::info!("Clicked!`") } )
+    /// rsx!( button { "click me", onclick: move |_| tracing::info!("Clicked!`") } )
     /// ```
     /// ```
     ///
     ///
     /// ## Reference
     /// ## Reference

+ 1 - 1
packages/liveview/Cargo.toml

@@ -11,7 +11,7 @@ license = "MIT OR Apache-2.0"
 
 
 [dependencies]
 [dependencies]
 thiserror = { workspace = true }
 thiserror = { workspace = true }
-log = { workspace = true }
+tracing = { workspace = true }
 slab = { workspace = true }
 slab = { workspace = true }
 futures-util = { workspace = true, default-features = false, features = [
 futures-util = { workspace = true, default-features = false, features = [
     "sink",
     "sink",

+ 1 - 1
packages/liveview/src/query.rs

@@ -126,7 +126,7 @@ impl QueryEngine {
                 }})
                 }})
             }})();"#
             }})();"#
         )) {
         )) {
-            log::warn!("Query error: {err}");
+            tracing::warn!("Query error: {err}");
         }
         }
 
 
         Query {
         Query {

+ 7 - 6
packages/router-macro/src/lib.rs

@@ -210,7 +210,7 @@ pub fn routable(input: TokenStream) -> TokenStream {
     let display_impl = route_enum.impl_display();
     let display_impl = route_enum.impl_display();
     let routable_impl = route_enum.routable_impl();
     let routable_impl = route_enum.routable_impl();
 
 
-    quote! {
+    (quote! {
         #error_type
         #error_type
 
 
         #display_impl
         #display_impl
@@ -218,7 +218,7 @@ pub fn routable(input: TokenStream) -> TokenStream {
         #routable_impl
         #routable_impl
 
 
         #parse_impl
         #parse_impl
-    }
+    })
     .into()
     .into()
 }
 }
 
 
@@ -482,7 +482,8 @@ impl RouteEnum {
                     let route = s;
                     let route = s;
                     let (route, _hash) = route.split_once('#').unwrap_or((route, ""));
                     let (route, _hash) = route.split_once('#').unwrap_or((route, ""));
                     let (route, query) = route.split_once('?').unwrap_or((route, ""));
                     let (route, query) = route.split_once('?').unwrap_or((route, ""));
-                    let mut segments = route.split('/');
+                    let query = dioxus_router::exports::urlencoding::decode(query).unwrap_or(query.into());
+                    let mut segments = route.split('/').map(|s| dioxus_router::exports::urlencoding::decode(s).unwrap_or(s.into()));
                     // skip the first empty segment
                     // skip the first empty segment
                     if s.starts_with('/') {
                     if s.starts_with('/') {
                         let _ = segments.next();
                         let _ = segments.next();
@@ -677,9 +678,9 @@ impl ToTokens for SegmentType {
 impl<'a> From<&'a RouteSegment> for SegmentType {
 impl<'a> From<&'a RouteSegment> for SegmentType {
     fn from(value: &'a RouteSegment) -> Self {
     fn from(value: &'a RouteSegment) -> Self {
         match value {
         match value {
-            segment::RouteSegment::Static(s) => SegmentType::Static(s.to_string()),
-            segment::RouteSegment::Dynamic(s, _) => SegmentType::Dynamic(s.to_string()),
-            segment::RouteSegment::CatchAll(s, _) => SegmentType::CatchAll(s.to_string()),
+            RouteSegment::Static(s) => SegmentType::Static(s.to_string()),
+            RouteSegment::Dynamic(s, _) => SegmentType::Dynamic(s.to_string()),
+            RouteSegment::CatchAll(s, _) => SegmentType::CatchAll(s.to_string()),
         }
         }
     }
     }
 }
 }

+ 1 - 1
packages/router-macro/src/query.rs

@@ -14,7 +14,7 @@ impl QuerySegment {
         let ident = &self.ident;
         let ident = &self.ident;
         let ty = &self.ty;
         let ty = &self.ty;
         quote! {
         quote! {
-            let #ident = <#ty as dioxus_router::routable::FromQuery>::from_query(query);
+            let #ident = <#ty as dioxus_router::routable::FromQuery>::from_query(&*query);
         }
         }
     }
     }
 
 

+ 6 - 3
packages/router-macro/src/route_tree.rs

@@ -312,7 +312,8 @@ impl<'a> RouteTreeSegmentData<'a> {
                 quote! {
                 quote! {
                     {
                     {
                         let mut segments = segments.clone();
                         let mut segments = segments.clone();
-                        if let Some(segment) = segments.next() {
+                        let segment = segments.next();
+                        if let Some(segment) = segment.as_deref() {
                             if #segment == segment {
                             if #segment == segment {
                                 #(#children)*
                                 #(#children)*
                             }
                             }
@@ -369,7 +370,7 @@ impl<'a> RouteTreeSegmentData<'a> {
                         quote! {
                         quote! {
                             let mut trailing = String::from("/");
                             let mut trailing = String::from("/");
                             for seg in segments.clone() {
                             for seg in segments.clone() {
-                                trailing += seg;
+                                trailing += &*seg;
                                 trailing += "/";
                                 trailing += "/";
                             }
                             }
                             trailing.pop();
                             trailing.pop();
@@ -506,7 +507,9 @@ fn return_constructed(
             let remaining_segments = segments.clone();
             let remaining_segments = segments.clone();
             let mut segments_clone = segments.clone();
             let mut segments_clone = segments.clone();
             let next_segment = segments_clone.next();
             let next_segment = segments_clone.next();
+            let next_segment = next_segment.as_deref();
             let segment_after_next = segments_clone.next();
             let segment_after_next = segments_clone.next();
+            let segment_after_next = segment_after_next.as_deref();
             match (next_segment, segment_after_next) {
             match (next_segment, segment_after_next) {
                 // This is the last segment, return the parsed route
                 // This is the last segment, return the parsed route
                 (None, _) | (Some(""), None) => {
                 (None, _) | (Some(""), None) => {
@@ -516,7 +519,7 @@ fn return_constructed(
                 _ => {
                 _ => {
                     let mut trailing = String::new();
                     let mut trailing = String::new();
                     for seg in remaining_segments {
                     for seg in remaining_segments {
-                        trailing += seg;
+                        trailing += &*seg;
                         trailing += "/";
                         trailing += "/";
                     }
                     }
                     trailing.pop();
                     trailing.pop();

+ 10 - 5
packages/router-macro/src/segment.rs

@@ -25,7 +25,7 @@ impl RouteSegment {
         match self {
         match self {
             Self::Static(segment) => quote! { write!(f, "/{}", #segment)?; },
             Self::Static(segment) => quote! { write!(f, "/{}", #segment)?; },
             Self::Dynamic(ident, _) => quote! { write!(f, "/{}", #ident)?; },
             Self::Dynamic(ident, _) => quote! { write!(f, "/{}", #ident)?; },
-            Self::CatchAll(ident, _) => quote! { #ident.display_route_segements(f)?; },
+            Self::CatchAll(ident, _) => quote! { #ident.display_route_segments(f)?; },
         }
         }
     }
     }
 
 
@@ -59,6 +59,7 @@ impl RouteSegment {
                     {
                     {
                         let mut segments = segments.clone();
                         let mut segments = segments.clone();
                         let segment = segments.next();
                         let segment = segments.next();
+                        let segment = segment.as_deref();
                         let parsed = if let Some(#segment) = segment {
                         let parsed = if let Some(#segment) = segment {
                             Ok(())
                             Ok(())
                         } else {
                         } else {
@@ -80,7 +81,8 @@ impl RouteSegment {
                 quote! {
                 quote! {
                     {
                     {
                         let mut segments = segments.clone();
                         let mut segments = segments.clone();
-                        let parsed = if let Some(segment) = segments.next() {
+                        let segment = segments.next();
+                        let parsed = if let Some(segment) = segment.as_deref() {
                             <#ty as dioxus_router::routable::FromRouteSegment>::from_route_segment(segment).map_err(|err| #error_enum_name::#error_enum_varient(#inner_parse_enum::#error_name(err)))
                             <#ty as dioxus_router::routable::FromRouteSegment>::from_route_segment(segment).map_err(|err| #error_enum_name::#error_enum_varient(#inner_parse_enum::#error_name(err)))
                         } else {
                         } else {
                             Err(#error_enum_name::#error_enum_varient(#inner_parse_enum::#missing_error_name))
                             Err(#error_enum_name::#error_enum_varient(#inner_parse_enum::#missing_error_name))
@@ -100,9 +102,12 @@ impl RouteSegment {
                 quote! {
                 quote! {
                     {
                     {
                         let parsed = {
                         let parsed = {
-                            let mut segments = segments.clone();
-                            let segments: Vec<_> = segments.collect();
-                            <#ty as dioxus_router::routable::FromRouteSegments>::from_route_segments(&segments).map_err(|err| #error_enum_name::#error_enum_varient(#inner_parse_enum::#error_name(err)))
+                            let remaining_segments: Vec<_> = segments.collect();
+                            let mut new_segments: Vec<&str> = Vec::new();
+                            for segment in &remaining_segments {
+                                new_segments.push(&*segment);
+                            }
+                            <#ty as dioxus_router::routable::FromRouteSegments>::from_route_segments(&new_segments).map_err(|err| #error_enum_name::#error_enum_varient(#inner_parse_enum::#error_name(err)))
                         };
                         };
                         match parsed {
                         match parsed {
                             Ok(#name) => {
                             Ok(#name) => {

+ 2 - 2
packages/router/Cargo.toml

@@ -14,10 +14,10 @@ anyhow = "1.0.66"
 dioxus = { workspace = true }
 dioxus = { workspace = true }
 dioxus-router-macro = { workspace = true }
 dioxus-router-macro = { workspace = true }
 gloo = { version = "0.8.0", optional = true }
 gloo = { version = "0.8.0", optional = true }
-log = { workspace = true }
+tracing = { workspace = true }
 thiserror = { workspace = true }
 thiserror = { workspace = true }
 futures-util = { workspace = true }
 futures-util = { workspace = true }
-serde_urlencoded = { version = "0.7.1", optional = true }
+urlencoding = "2.1.3"
 serde = { version = "1", features = ["derive"], optional = true }
 serde = { version = "1", features = ["derive"], optional = true }
 url = "2.3.1"
 url = "2.3.1"
 wasm-bindgen = { workspace = true, optional = true }
 wasm-bindgen = { workspace = true, optional = true }

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

@@ -1,5 +1,5 @@
 use dioxus::prelude::*;
 use dioxus::prelude::*;
-use log::error;
+use tracing::error;
 
 
 use crate::utils::use_router_internal::use_router_internal;
 use crate::utils::use_router_internal::use_router_internal;
 
 

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

@@ -3,7 +3,7 @@ use std::fmt::Debug;
 use std::rc::Rc;
 use std::rc::Rc;
 
 
 use dioxus::prelude::*;
 use dioxus::prelude::*;
-use log::error;
+use tracing::error;
 
 
 use crate::navigation::NavigationTarget;
 use crate::navigation::NavigationTarget;
 use crate::prelude::Routable;
 use crate::prelude::Routable;

+ 1 - 1
packages/router/src/history/web.rs

@@ -139,7 +139,7 @@ impl<R: Routable> WebHistory<R> {
         );
         );
 
 
         let current_route = myself.current_route();
         let current_route = myself.current_route();
-        log::trace!("initial route: {:?}", current_route);
+        tracing::trace!("initial route: {:?}", current_route);
         let current_url = current_route.to_string();
         let current_url = current_route.to_string();
         let state = myself.create_state(current_route);
         let state = myself.create_state(current_route);
         let _ = replace_state_with_url(&myself.history, &state, Some(&current_url));
         let _ = replace_state_with_url(&myself.history, &state, Some(&current_url));

+ 1 - 1
packages/router/src/history/web_hash.rs

@@ -1,8 +1,8 @@
 use std::sync::{Arc, Mutex};
 use std::sync::{Arc, Mutex};
 
 
 use gloo::{events::EventListener, render::AnimationFrame, utils::window};
 use gloo::{events::EventListener, render::AnimationFrame, utils::window};
-use log::error;
 use serde::{de::DeserializeOwned, Serialize};
 use serde::{de::DeserializeOwned, Serialize};
+use tracing::error;
 use url::Url;
 use url::Url;
 use web_sys::{History, ScrollRestoration, Window};
 use web_sys::{History, ScrollRestoration, Window};
 
 

+ 2 - 2
packages/router/src/incremental.rs

@@ -59,8 +59,8 @@ where
                     .await?;
                     .await?;
                 }
                 }
                 Err(e) => {
                 Err(e) => {
-                    log::info!("@ route: {}", full_path);
-                    log::error!("Error pre-caching static route: {}", e);
+                    tracing::info!("@ route: {}", full_path);
+                    tracing::error!("Error pre-caching static route: {}", e);
                 }
                 }
             }
             }
         }
         }

+ 5 - 0
packages/router/src/lib.rs

@@ -82,3 +82,8 @@ pub mod prelude {
 mod utils {
 mod utils {
     pub(crate) mod use_router_internal;
     pub(crate) mod use_router_internal;
 }
 }
+
+#[doc(hidden)]
+pub mod exports {
+    pub use urlencoding;
+}

+ 119 - 64
packages/router/src/routable.rs

@@ -3,16 +3,18 @@
 #![allow(non_snake_case)]
 #![allow(non_snake_case)]
 use dioxus::prelude::*;
 use dioxus::prelude::*;
 
 
+use std::iter::FlatMap;
+use std::slice::Iter;
 use std::{fmt::Display, str::FromStr};
 use std::{fmt::Display, str::FromStr};
 
 
-/// An error that occurs when parsing a route
+/// An error that occurs when parsing a route.
 #[derive(Debug, PartialEq)]
 #[derive(Debug, PartialEq)]
-pub struct RouteParseError<E: std::fmt::Display> {
-    /// The attempted routes that failed to match
+pub struct RouteParseError<E: Display> {
+    /// The attempted routes that failed to match.
     pub attempted_routes: Vec<E>,
     pub attempted_routes: Vec<E>,
 }
 }
 
 
-impl<E: std::fmt::Display> std::fmt::Display for RouteParseError<E> {
+impl<E: Display> Display for RouteParseError<E> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         write!(f, "Route did not match:\nAttempted Matches:\n")?;
         write!(f, "Route did not match:\nAttempted Matches:\n")?;
         for (i, route) in self.attempted_routes.iter().enumerate() {
         for (i, route) in self.attempted_routes.iter().enumerate() {
@@ -26,63 +28,96 @@ impl<E: std::fmt::Display> std::fmt::Display for RouteParseError<E> {
 ///
 ///
 /// This trait needs to be implemented if you want to turn a query string into a struct.
 /// This trait needs to be implemented if you want to turn a query string into a struct.
 ///
 ///
-/// A working example can be found in the `examples` folder in the root package under `query_segments_demo`
+/// A working example can be found in the `examples` folder in the root package under `query_segments_demo`.
 pub trait FromQuery {
 pub trait FromQuery {
-    /// Create an instance of `Self` from a query string
+    /// Create an instance of `Self` from a query string.
     fn from_query(query: &str) -> Self;
     fn from_query(query: &str) -> Self;
 }
 }
 
 
 impl<T: for<'a> From<&'a str>> FromQuery for T {
 impl<T: for<'a> From<&'a str>> FromQuery for T {
     fn from_query(query: &str) -> Self {
     fn from_query(query: &str) -> Self {
-        T::from(query)
+        T::from(&*urlencoding::decode(query).expect("Failed to decode url encoding"))
     }
     }
 }
 }
 
 
-/// Something that can be created from a route segment
+/// Something that can be created from a route segment.
 pub trait FromRouteSegment: Sized {
 pub trait FromRouteSegment: Sized {
-    /// The error that can occur when parsing a route segment
+    /// The error that can occur when parsing a route segment.
     type Err;
     type Err;
 
 
-    /// Create an instance of `Self` from a route segment
+    /// Create an instance of `Self` from a route segment.
     fn from_route_segment(route: &str) -> Result<Self, Self::Err>;
     fn from_route_segment(route: &str) -> Result<Self, Self::Err>;
 }
 }
 
 
 impl<T: FromStr> FromRouteSegment for T
 impl<T: FromStr> FromRouteSegment for T
 where
 where
-    <T as FromStr>::Err: std::fmt::Display,
+    <T as FromStr>::Err: Display,
 {
 {
     type Err = <T as FromStr>::Err;
     type Err = <T as FromStr>::Err;
 
 
     fn from_route_segment(route: &str) -> Result<Self, Self::Err> {
     fn from_route_segment(route: &str) -> Result<Self, Self::Err> {
-        T::from_str(route)
+        match urlencoding::decode(route) {
+            Ok(segment) => T::from_str(&segment),
+            Err(err) => {
+                tracing::error!("Failed to decode url encoding: {}", err);
+                T::from_str(route)
+            }
+        }
     }
     }
 }
 }
 
 
-/// Something that can be converted to route segments
+#[test]
+fn full_circle() {
+    let route = "testing 1234 hello world";
+    assert_eq!(String::from_route_segment(route).unwrap(), route);
+}
+
+/// Something that can be converted to route segments.
 pub trait ToRouteSegments {
 pub trait ToRouteSegments {
-    /// Display the route segments
-    fn display_route_segements(self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result;
+    /// Display the route segments.
+    fn display_route_segments(self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result;
 }
 }
 
 
-impl<I, T: std::fmt::Display> ToRouteSegments for I
+impl<I, T: Display> ToRouteSegments for I
 where
 where
     I: IntoIterator<Item = T>,
     I: IntoIterator<Item = T>,
 {
 {
-    fn display_route_segements(self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+    fn display_route_segments(self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         for segment in self {
         for segment in self {
             write!(f, "/")?;
             write!(f, "/")?;
-            write!(f, "{}", segment)?;
+            let segment = segment.to_string();
+            match urlencoding::decode(&segment) {
+                Ok(segment) => write!(f, "{}", segment)?,
+                Err(err) => {
+                    tracing::error!("Failed to decode url encoding: {}", err);
+                    write!(f, "{}", segment)?
+                }
+            }
         }
         }
         Ok(())
         Ok(())
     }
     }
 }
 }
 
 
-/// Something that can be created from route segments
+#[test]
+fn to_route_segments() {
+    struct DisplaysRoute;
+
+    impl Display for DisplaysRoute {
+        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+            let segments = vec!["hello", "world"];
+            segments.display_route_segments(f)
+        }
+    }
+
+    assert_eq!(DisplaysRoute.to_string(), "/hello/world");
+}
+
+/// Something that can be created from route segments.
 pub trait FromRouteSegments: Sized {
 pub trait FromRouteSegments: Sized {
-    /// The error that can occur when parsing route segments
+    /// The error that can occur when parsing route segments.
     type Err;
     type Err;
 
 
-    /// Create an instance of `Self` from route segments
+    /// Create an instance of `Self` from route segments.
     fn from_route_segments(segments: &[&str]) -> Result<Self, Self::Err>;
     fn from_route_segments(segments: &[&str]) -> Result<Self, Self::Err>;
 }
 }
 
 
@@ -97,20 +132,45 @@ impl<I: std::iter::FromIterator<String>> FromRouteSegments for I {
     }
     }
 }
 }
 
 
+/// A flattened version of [`Routable::SITE_MAP`].
+/// This essentially represents a `Vec<Vec<SegmentType>>`, which you can collect it into.
+type SiteMapFlattened<'a> = FlatMap<
+    Iter<'a, SiteMapSegment>,
+    Vec<Vec<SegmentType>>,
+    fn(&SiteMapSegment) -> Vec<Vec<SegmentType>>,
+>;
+
+fn seg_strs_to_route<T>(segs_maybe: &Option<Vec<&str>>) -> Option<T>
+where
+    T: Routable,
+{
+    if let Some(str) = seg_strs_to_str(segs_maybe) {
+        T::from_str(&str).ok()
+    } else {
+        None
+    }
+}
+
+fn seg_strs_to_str(segs_maybe: &Option<Vec<&str>>) -> Option<String> {
+    segs_maybe
+        .as_ref()
+        .map(|segs| String::from('/') + &segs.join("/"))
+}
+
 /// Something that can be:
 /// Something that can be:
-/// 1. Converted from a route
-/// 2. Converted to a route
-/// 3. Rendered as a component
+/// 1. Converted from a route.
+/// 2. Converted to a route.
+/// 3. Rendered as a component.
 ///
 ///
-/// This trait can be derived using the `#[derive(Routable)]` macro
-pub trait Routable: std::fmt::Display + std::str::FromStr + Clone + 'static {
-    /// The error that can occur when parsing a route
+/// This trait can be derived using the `#[derive(Routable)]` macro.
+pub trait Routable: FromStr + Display + Clone + 'static {
+    /// The error that can occur when parsing a route.
     const SITE_MAP: &'static [SiteMapSegment];
     const SITE_MAP: &'static [SiteMapSegment];
 
 
     /// Render the route at the given level
     /// Render the route at the given level
     fn render<'a>(&self, cx: &'a ScopeState, level: usize) -> Element<'a>;
     fn render<'a>(&self, cx: &'a ScopeState, level: usize) -> Element<'a>;
 
 
-    /// Checks if this route is a child of the given route
+    /// Checks if this route is a child of the given route.
     ///
     ///
     /// # Example
     /// # Example
     /// ```rust
     /// ```rust
@@ -152,7 +212,7 @@ pub trait Routable: std::fmt::Display + std::str::FromStr + Clone + 'static {
         true
         true
     }
     }
 
 
-    /// Get the parent route of this route
+    /// Get the parent route of this route.
     ///
     ///
     /// # Example
     /// # Example
     /// ```rust
     /// ```rust
@@ -192,72 +252,67 @@ pub trait Routable: std::fmt::Display + std::str::FromStr + Clone + 'static {
         Self::from_str(&new_route).ok()
         Self::from_str(&new_route).ok()
     }
     }
 
 
-    /// Gets a list of all static routes
+    /// Returns a flattened version of [`Self::SITE_MAP`].
+    fn flatten_site_map<'a>() -> SiteMapFlattened<'a> {
+        Self::SITE_MAP.iter().flat_map(SiteMapSegment::flatten)
+    }
+
+    /// Gets a list of all the static routes.
+    /// Example static route: `#[route("/static/route")]`
     fn static_routes() -> Vec<Self> {
     fn static_routes() -> Vec<Self> {
-        Self::SITE_MAP
-            .iter()
-            .flat_map(|segment| segment.flatten())
+        Self::flatten_site_map()
             .filter_map(|route| {
             .filter_map(|route| {
-                if route
+                let route_if_static = &route
                     .iter()
                     .iter()
-                    .all(|segment| matches!(segment, SegmentType::Static(_)))
-                {
-                    Self::from_str(
-                        &route
-                            .iter()
-                            .map(|segment| match segment {
-                                SegmentType::Static(s) => s.to_string(),
-                                _ => unreachable!(),
-                            })
-                            .collect::<Vec<_>>()
-                            .join("/"),
-                    )
-                    .ok()
-                } else {
-                    None
-                }
+                    .map(|segment| match segment {
+                        SegmentType::Static(s) => Some(*s),
+                        _ => None,
+                    })
+                    .collect::<Option<Vec<_>>>();
+
+                seg_strs_to_route(route_if_static)
             })
             })
             .collect()
             .collect()
     }
     }
 }
 }
 
 
 trait RoutableFactory {
 trait RoutableFactory {
-    type Err: std::fmt::Display;
+    type Err: Display;
     type Routable: Routable + FromStr<Err = Self::Err>;
     type Routable: Routable + FromStr<Err = Self::Err>;
 }
 }
 
 
 impl<R: Routable + FromStr> RoutableFactory for R
 impl<R: Routable + FromStr> RoutableFactory for R
 where
 where
-    <R as FromStr>::Err: std::fmt::Display,
+    <R as FromStr>::Err: Display,
 {
 {
     type Err = <R as FromStr>::Err;
     type Err = <R as FromStr>::Err;
     type Routable = R;
     type Routable = R;
 }
 }
 
 
-trait RouteRenderable: std::fmt::Display + 'static {
+trait RouteRenderable: Display + 'static {
     fn render<'a>(&self, cx: &'a ScopeState, level: usize) -> Element<'a>;
     fn render<'a>(&self, cx: &'a ScopeState, level: usize) -> Element<'a>;
 }
 }
 
 
 impl<R: Routable> RouteRenderable for R
 impl<R: Routable> RouteRenderable for R
 where
 where
-    <R as FromStr>::Err: std::fmt::Display,
+    <R as FromStr>::Err: Display,
 {
 {
     fn render<'a>(&self, cx: &'a ScopeState, level: usize) -> Element<'a> {
     fn render<'a>(&self, cx: &'a ScopeState, level: usize) -> Element<'a> {
         self.render(cx, level)
         self.render(cx, level)
     }
     }
 }
 }
 
 
-/// A type erased map of the site structurens
+/// A type erased map of the site structure.
 #[derive(Debug, Clone, PartialEq)]
 #[derive(Debug, Clone, PartialEq)]
 pub struct SiteMapSegment {
 pub struct SiteMapSegment {
-    /// The type of the route segment
+    /// The type of the route segment.
     pub segment_type: SegmentType,
     pub segment_type: SegmentType,
-    /// The children of the route segment
+    /// The children of the route segment.
     pub children: &'static [SiteMapSegment],
     pub children: &'static [SiteMapSegment],
 }
 }
 
 
 impl SiteMapSegment {
 impl SiteMapSegment {
-    /// Take a map of the site structure and flatten it into a vector of routes
+    /// Take a map of the site structure and flatten it into a vector of routes.
     pub fn flatten(&self) -> Vec<Vec<SegmentType>> {
     pub fn flatten(&self) -> Vec<Vec<SegmentType>> {
         let mut routes = Vec::new();
         let mut routes = Vec::new();
         self.flatten_inner(&mut routes, Vec::new());
         self.flatten_inner(&mut routes, Vec::new());
@@ -277,16 +332,16 @@ impl SiteMapSegment {
     }
     }
 }
 }
 
 
-/// The type of a route segment
+/// The type of a route segment.
 #[derive(Debug, Clone, PartialEq)]
 #[derive(Debug, Clone, PartialEq)]
 pub enum SegmentType {
 pub enum SegmentType {
-    /// A static route segment
+    /// A static route segment.
     Static(&'static str),
     Static(&'static str),
-    /// A dynamic route segment
+    /// A dynamic route segment.
     Dynamic(&'static str),
     Dynamic(&'static str),
-    /// A catch all route segment
+    /// A catch all route segment.
     CatchAll(&'static str),
     CatchAll(&'static str),
-    /// A child router
+    /// A child router.
     Child,
     Child,
 }
 }
 
 
@@ -296,7 +351,7 @@ impl Display for SegmentType {
             SegmentType::Static(s) => write!(f, "/{}", s),
             SegmentType::Static(s) => write!(f, "/{}", s),
             SegmentType::Child => Ok(()),
             SegmentType::Child => Ok(()),
             SegmentType::Dynamic(s) => write!(f, "/:{}", s),
             SegmentType::Dynamic(s) => write!(f, "/:{}", s),
-            SegmentType::CatchAll(s) => write!(f, "/:...{}", s),
+            SegmentType::CatchAll(s) => write!(f, "/:..{}", s),
         }
         }
     }
     }
 }
 }

+ 1 - 1
packages/signals/Cargo.toml

@@ -9,7 +9,7 @@ edition = "2018"
 [dependencies]
 [dependencies]
 dioxus-core = { workspace = true }
 dioxus-core = { workspace = true }
 generational-box = { workspace = true }
 generational-box = { workspace = true }
-log.workspace = true
+tracing = { workspace = true }
 simple_logger = "4.2.0"
 simple_logger = "4.2.0"
 serde = { version = "1", features = ["derive"], optional = true }
 serde = { version = "1", features = ["derive"], optional = true }
 
 

+ 3 - 3
packages/signals/src/signal.rs

@@ -177,7 +177,7 @@ impl<T: 'static> Signal<T> {
         } else if let Some(current_scope_id) = current_scope_id() {
         } else if let Some(current_scope_id) = current_scope_id() {
             // only subscribe if the vdom is rendering
             // only subscribe if the vdom is rendering
             if dioxus_core::vdom_is_rendering() {
             if dioxus_core::vdom_is_rendering() {
-                log::trace!(
+                tracing::trace!(
                     "{:?} subscribed to {:?}",
                     "{:?} subscribed to {:?}",
                     self.inner.value,
                     self.inner.value,
                     current_scope_id
                     current_scope_id
@@ -209,7 +209,7 @@ impl<T: 'static> Signal<T> {
         {
         {
             let inner = self.inner.read();
             let inner = self.inner.read();
             for &scope_id in &*inner.subscribers.borrow() {
             for &scope_id in &*inner.subscribers.borrow() {
-                log::trace!(
+                tracing::trace!(
                     "Write on {:?} triggered update on {:?}",
                     "Write on {:?} triggered update on {:?}",
                     self.inner.value,
                     self.inner.value,
                     scope_id
                     scope_id
@@ -224,7 +224,7 @@ impl<T: 'static> Signal<T> {
             std::mem::take(&mut *effects)
             std::mem::take(&mut *effects)
         };
         };
         for effect in subscribers {
         for effect in subscribers {
-            log::trace!(
+            tracing::trace!(
                 "Write on {:?} triggered effect {:?}",
                 "Write on {:?} triggered effect {:?}",
                 self.inner.value,
                 self.inner.value,
                 effect
                 effect

+ 2 - 2
packages/ssr/Cargo.toml

@@ -15,14 +15,14 @@ askama_escape = "0.10.3"
 thiserror = "1.0.23"
 thiserror = "1.0.23"
 rustc-hash = "1.1.0"
 rustc-hash = "1.1.0"
 lru = "0.10.0"
 lru = "0.10.0"
-log = "0.4.13"
+tracing = { workspace = true }
 http = "0.2.9"
 http = "0.2.9"
 tokio = { version = "1.28", features = ["full"], optional = true }
 tokio = { version = "1.28", features = ["full"], optional = true }
 
 
 [dev-dependencies]
 [dev-dependencies]
 dioxus = { workspace = true }
 dioxus = { workspace = true }
 thiserror = { workspace = true }
 thiserror = { workspace = true }
-log = { workspace = true }
+tracing = { workspace = true }
 fern = { version = "0.6.0", features = ["colored"] }
 fern = { version = "0.6.0", features = ["colored"] }
 anyhow = "1.0"
 anyhow = "1.0"
 argh = "0.1.4"
 argh = "0.1.4"

+ 5 - 5
packages/ssr/src/incremental.rs

@@ -139,13 +139,13 @@ impl IncrementalRenderer {
                 let age = elapsed.as_secs();
                 let age = elapsed.as_secs();
                 if let Some(invalidate_after) = self.invalidate_after {
                 if let Some(invalidate_after) = self.invalidate_after {
                     if elapsed < invalidate_after {
                     if elapsed < invalidate_after {
-                        log::trace!("memory cache hit {:?}", route);
+                        tracing::trace!("memory cache hit {:?}", route);
                         output.write_all(cache_hit).await?;
                         output.write_all(cache_hit).await?;
                         let max_age = invalidate_after.as_secs();
                         let max_age = invalidate_after.as_secs();
                         return Ok(Some(RenderFreshness::new(age, max_age)));
                         return Ok(Some(RenderFreshness::new(age, max_age)));
                     }
                     }
                 } else {
                 } else {
-                    log::trace!("memory cache hit {:?}", route);
+                    tracing::trace!("memory cache hit {:?}", route);
                     output.write_all(cache_hit).await?;
                     output.write_all(cache_hit).await?;
                     return Ok(Some(RenderFreshness::new_age(age)));
                     return Ok(Some(RenderFreshness::new_age(age)));
                 }
                 }
@@ -157,7 +157,7 @@ impl IncrementalRenderer {
                 if let Ok(file) = tokio::fs::File::open(file_path.full_path).await {
                 if let Ok(file) = tokio::fs::File::open(file_path.full_path).await {
                     let mut file = BufReader::new(file);
                     let mut file = BufReader::new(file);
                     tokio::io::copy_buf(&mut file, output).await?;
                     tokio::io::copy_buf(&mut file, output).await?;
-                    log::trace!("file cache hit {:?}", route);
+                    tracing::trace!("file cache hit {:?}", route);
                     self.promote_memory_cache(&route);
                     self.promote_memory_cache(&route);
                     return Ok(Some(freshness));
                     return Ok(Some(freshness));
                 }
                 }
@@ -184,7 +184,7 @@ impl IncrementalRenderer {
             let freshness = self
             let freshness = self
                 .render_and_cache(route, component, props, output, rebuild_with, renderer)
                 .render_and_cache(route, component, props, output, rebuild_with, renderer)
                 .await?;
                 .await?;
-            log::trace!("cache miss");
+            tracing::trace!("cache miss");
             Ok(freshness)
             Ok(freshness)
         }
         }
     }
     }
@@ -206,7 +206,7 @@ impl IncrementalRenderer {
                         }
                         }
                         // if the timestamp is invalid or passed, delete the file
                         // if the timestamp is invalid or passed, delete the file
                         if let Err(err) = std::fs::remove_file(entry.path()) {
                         if let Err(err) = std::fs::remove_file(entry.path()) {
-                            log::error!("Failed to remove file: {}", err);
+                            tracing::error!("Failed to remove file: {}", err);
                         }
                         }
                     }
                     }
                 }
                 }

+ 2 - 1
packages/web/Cargo.toml

@@ -20,7 +20,7 @@ dioxus-interpreter-js = { workspace = true, features = [
 js-sys = "0.3.56"
 js-sys = "0.3.56"
 wasm-bindgen = { workspace = true, features = ["enable-interning"] }
 wasm-bindgen = { workspace = true, features = ["enable-interning"] }
 wasm-bindgen-futures = "0.4.29"
 wasm-bindgen-futures = "0.4.29"
-log = { workspace = true }
+tracing = { workspace = true }
 rustc-hash = { workspace = true }
 rustc-hash = { workspace = true }
 console_error_panic_hook = { version = "0.1.7", optional = true }
 console_error_panic_hook = { version = "0.1.7", optional = true }
 futures-util = { workspace = true, features = ["std", "async-await", "async-await-macro"] }
 futures-util = { workspace = true, features = ["std", "async-await", "async-await-macro"] }
@@ -75,3 +75,4 @@ wasm-logger = "0.2.0"
 gloo-timers = "0.2.3"
 gloo-timers = "0.2.3"
 gloo-dialogs = "0.1.1"
 gloo-dialogs = "0.1.1"
 dioxus-web = { path = ".", features = ["hydrate"] }
 dioxus-web = { path = ".", features = ["hydrate"] }
+tracing-wasm = "0.2.1"

+ 2 - 2
packages/web/examples/hydrate.rs

@@ -43,13 +43,13 @@ fn Bapp(cx: Scope) -> Element {
 
 
 fn main() {
 fn main() {
     console_error_panic_hook::set_once();
     console_error_panic_hook::set_once();
-    wasm_logger::init(wasm_logger::Config::new(log::Level::Trace));
+    tracing_wasm::set_as_global_default();
 
 
     let mut dom = VirtualDom::new(app);
     let mut dom = VirtualDom::new(app);
     let _ = dom.rebuild();
     let _ = dom.rebuild();
 
 
     let pre = dioxus_ssr::pre_render(&dom);
     let pre = dioxus_ssr::pre_render(&dom);
-    log::trace!("{}", pre);
+    tracing::trace!("{}", pre);
 
 
     // set the inner content of main to the pre-rendered content
     // set the inner content of main to the pre-rendered content
     window()
     window()

+ 0 - 1
packages/web/src/dom.rs

@@ -249,7 +249,6 @@ impl WebsysDom {
         for id in to_mount {
         for id in to_mount {
             let node = get_node(id.0 as u32);
             let node = get_node(id.0 as u32);
             if let Some(element) = node.dyn_ref::<Element>() {
             if let Some(element) = node.dyn_ref::<Element>() {
-                log::info!("mounted event fired: {}", id.0);
                 let data: MountedData = element.into();
                 let data: MountedData = element.into();
                 let data = Rc::new(data);
                 let data = Rc::new(data);
                 let _ = self.event_channel.unbounded_send(UiEvent {
                 let _ = self.event_channel.unbounded_send(UiEvent {

+ 1 - 1
packages/web/src/eval.rs

@@ -46,7 +46,7 @@ impl WebEvaluator {
                 Ok(data) => _ = channel_sender.send_blocking(data),
                 Ok(data) => _ = channel_sender.send_blocking(data),
                 Err(e) => {
                 Err(e) => {
                     // Can't really do much here.
                     // Can't really do much here.
-                    log::error!("failed to serialize JsValue to serde_json::Value (eval communication) - {}", e);
+                    tracing::error!("failed to serialize JsValue to serde_json::Value (eval communication) - {}", e);
                 }
                 }
             }
             }
         });
         });

+ 4 - 4
packages/web/src/lib.rs

@@ -170,7 +170,7 @@ pub fn launch_with_props<T: 'static>(
 /// }
 /// }
 /// ```
 /// ```
 pub async fn run_with_props<T: 'static>(root: fn(Scope<T>) -> Element, root_props: T, cfg: Config) {
 pub async fn run_with_props<T: 'static>(root: fn(Scope<T>) -> Element, root_props: T, cfg: Config) {
-    log::info!("Starting up");
+    tracing::info!("Starting up");
 
 
     let mut dom = VirtualDom::new_with_props(root, root_props);
     let mut dom = VirtualDom::new_with_props(root, root_props);
 
 
@@ -205,7 +205,7 @@ pub async fn run_with_props<T: 'static>(root: fn(Scope<T>) -> Element, root_prop
 
 
     let mut websys_dom = dom::WebsysDom::new(cfg, tx);
     let mut websys_dom = dom::WebsysDom::new(cfg, tx);
 
 
-    log::info!("rebuilding app");
+    tracing::info!("rebuilding app");
 
 
     if should_hydrate {
     if should_hydrate {
         #[cfg(feature = "hydrate")]
         #[cfg(feature = "hydrate")]
@@ -217,7 +217,7 @@ pub async fn run_with_props<T: 'static>(root: fn(Scope<T>) -> Element, root_prop
             websys_dom.load_templates(&templates);
             websys_dom.load_templates(&templates);
 
 
             if let Err(err) = websys_dom.rehydrate(&dom) {
             if let Err(err) = websys_dom.rehydrate(&dom) {
-                log::error!(
+                tracing::error!(
                     "Rehydration failed {:?}. Rebuild DOM into element from scratch",
                     "Rehydration failed {:?}. Rebuild DOM into element from scratch",
                     &err
                     &err
                 );
                 );
@@ -240,7 +240,7 @@ pub async fn run_with_props<T: 'static>(root: fn(Scope<T>) -> Element, root_prop
     websys_dom.mount();
     websys_dom.mount();
 
 
     loop {
     loop {
-        log::trace!("waiting for work");
+        tracing::trace!("waiting for work");
 
 
         // if virtualdom has nothing, wait for it to have something before requesting idle time
         // if virtualdom has nothing, wait for it to have something before requesting idle time
         // if there is work then this future resolves immediately.
         // if there is work then this future resolves immediately.

+ 4 - 4
packages/web/src/rehydrate.rs

@@ -114,9 +114,9 @@ impl WebsysDom {
         node: &TemplateNode,
         node: &TemplateNode,
         last_node_was_static_text: &mut bool,
         last_node_was_static_text: &mut bool,
     ) -> Result<(), RehydrationError> {
     ) -> Result<(), RehydrationError> {
-        log::trace!("rehydrate template node: {:?}", node);
+        tracing::trace!("rehydrate template node: {:?}", node);
         if let Ok(current_child) = current_child {
         if let Ok(current_child) = current_child {
-            if log::log_enabled!(log::Level::Trace) {
+            if tracing::event_enabled!(tracing::Level::TRACE) {
                 web_sys::console::log_1(&current_child.clone().into());
                 web_sys::console::log_1(&current_child.clone().into());
             }
             }
         }
         }
@@ -203,9 +203,9 @@ impl WebsysDom {
         dynamic: &DynamicNode,
         dynamic: &DynamicNode,
         last_node_was_static_text: &mut bool,
         last_node_was_static_text: &mut bool,
     ) -> Result<(), RehydrationError> {
     ) -> Result<(), RehydrationError> {
-        log::trace!("rehydrate dynamic node: {:?}", dynamic);
+        tracing::trace!("rehydrate dynamic node: {:?}", dynamic);
         if let Ok(current_child) = current_child {
         if let Ok(current_child) = current_child {
-            if log::log_enabled!(log::Level::Trace) {
+            if tracing::event_enabled!(tracing::Level::TRACE) {
                 web_sys::console::log_1(&current_child.clone().into());
                 web_sys::console::log_1(&current_child.clone().into());
             }
             }
         }
         }