浏览代码

Merge branch 'main' into fix-effect

Evan Almloff 1 年之前
父节点
当前提交
3827378f68
共有 49 个文件被更改,包括 1101 次插入671 次删除
  1. 0 12
      .github/free_space.sh
  2. 0 56
      .github/workflows/cli_release.yml
  3. 0 43
      .github/workflows/docs stable.yml
  4. 0 38
      .github/workflows/docs.yml
  5. 39 30
      .github/workflows/main.yml
  6. 92 0
      .github/workflows/merge.yml
  7. 48 0
      .github/workflows/promote.yml
  8. 155 0
      .github/workflows/publish.yml
  9. 0 37
      .github/workflows/wipe_cache.yml
  10. 240 223
      Cargo.lock
  11. 37 36
      Cargo.toml
  12. 2 2
      examples/PWA-example/Cargo.toml
  13. 2 2
      examples/future.rs
  14. 1 0
      examples/tailwind/.gitignore
  15. 1 1
      packages/cli-config/Cargo.toml
  16. 1 1
      packages/cli/Cargo.toml
  17. 2 0
      packages/core/Cargo.toml
  18. 39 4
      packages/core/src/virtual_dom.rs
  19. 5 9
      packages/core/tests/fuzzing.rs
  20. 82 0
      packages/core/tests/tracing.rs
  21. 3 2
      packages/desktop/headless_tests/events.rs
  22. 4 3
      packages/desktop/src/protocol.rs
  23. 1 2
      packages/extension/Cargo.toml
  24. 2 2
      packages/extension/package.json
  25. 3 3
      packages/fullstack/Cargo.toml
  26. 1 1
      packages/generational-box/Cargo.toml
  27. 30 0
      packages/hooks/src/use_context.rs
  28. 2 1
      packages/hooks/src/use_coroutine.rs
  29. 15 3
      packages/hooks/src/use_effect.rs
  30. 26 2
      packages/hooks/src/use_future.rs
  31. 25 1
      packages/hooks/src/use_resource.rs
  32. 1 1
      packages/html-internal-macro/Cargo.toml
  33. 4 4
      packages/html/src/elements.rs
  34. 2 2
      packages/html/src/global_attributes.rs
  35. 1 1
      packages/interpreter/Cargo.toml
  36. 1 1
      packages/interpreter/src/common.js
  37. 79 0
      packages/interpreter/src/common_exported.js
  38. 29 38
      packages/interpreter/src/interpreter.js
  39. 1 1
      packages/interpreter/src/lib.rs
  40. 105 99
      packages/interpreter/src/sledgehammer_bindings.rs
  41. 3 2
      packages/liveview/src/main.js
  42. 1 0
      packages/router-macro/src/lib.rs
  43. 1 0
      packages/router-macro/src/segment.rs
  44. 2 2
      packages/signals/Cargo.toml
  45. 3 1
      packages/signals/src/read.rs
  46. 1 1
      packages/ssr/Cargo.toml
  47. 1 0
      packages/web/src/dom.rs
  48. 2 2
      packages/web/src/mutations.rs
  49. 6 2
      packages/web/src/rehydrate.rs

+ 0 - 12
.github/free_space.sh

@@ -1,12 +0,0 @@
-df -h
-sudo rm -rf ${GITHUB_WORKSPACE}/.git
-sudo rm -rf "$AGENT_TOOLSDIRECTORY"
-sudo rm -rf /usr/share/dotnet
-sudo apt-get remove -y '^ghc-8.*'
-sudo apt-get remove -y '^dotnet-.*'
-sudo apt-get remove -y '^llvm-.*'
-sudo apt-get remove -y 'php.*'
-sudo apt-get remove -y azure-cli google-cloud-sdk hhvm google-chrome-stable firefox powershell mono-devel
-sudo apt-get autoremove -y
-sudo apt-get clean
-df -h

+ 0 - 56
.github/workflows/cli_release.yml

@@ -1,56 +0,0 @@
-name: Build CLI for Release
-
-# Will run automatically on every new release
-on:
-  release:
-    types: [published]
-
-jobs:
-  build-and-upload:
-    permissions:
-      contents: write
-    runs-on: ${{ matrix.platform.os }}
-    strategy:
-      matrix:
-        platform:
-          - {
-              target: x86_64-pc-windows-msvc,
-              os: windows-latest,
-              toolchain: "1.70.0",
-            }
-          - {
-              target: x86_64-apple-darwin,
-              os: macos-latest,
-              toolchain: "1.70.0",
-            }
-          - {
-              target: x86_64-unknown-linux-gnu,
-              os: ubuntu-latest,
-              toolchain: "1.70.0",
-            }
-    steps:
-      - uses: actions/checkout@v4
-      - name: Install stable
-        uses: dtolnay/rust-toolchain@master
-        with:
-          toolchain: ${{ matrix.platform.toolchain }}
-          targets: ${{ matrix.platform.target }}
-
-      - uses: ilammy/setup-nasm@v1
-
-      # Setup the Github Actions Cache for the CLI package
-      - name: Setup cache
-        uses: Swatinem/rust-cache@v2
-        with:
-          workspaces: packages/cli -> ../../target
-
-      # This neat action can build and upload the binary in one go!
-      - name: Build and upload binary
-        uses: taiki-e/upload-rust-binary-action@v1
-        with:
-          token: ${{ secrets.GITHUB_TOKEN }}
-          target: ${{ matrix.platform.target }}
-          bin: dx
-          archive: dx-${{ matrix.platform.target }}
-          checksum: sha256
-          manifest_path: packages/cli/Cargo.toml

+ 0 - 43
.github/workflows/docs stable.yml

@@ -1,43 +0,0 @@
-name: docs stable
-
-on:
-  workflow_dispatch:
-
-concurrency:
-  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
-  cancel-in-progress: true
-
-jobs:
-  build-deploy:
-    runs-on: ubuntu-latest
-    environment: docs
-    steps:
-
-      # NOTE: Comment out when https://github.com/rust-lang/mdBook/pull/1306 is merged and released
-      # - name: Setup mdBook
-      #   uses: peaceiris/actions-mdbook@v1
-      #   with:
-      #     mdbook-version: "0.4.10"
-
-      # NOTE: Delete when the previous one is enabled
-      - name: Setup mdBook
-        run: |
-          cargo install mdbook --git https://github.com/Demonthos/mdBook.git --branch master
-      - uses: actions/checkout@v4
-
-      - name: Build
-        run: cd docs &&
-          cd guide && mdbook build -d ../nightly/guide && cd .. &&
-          cd router && mdbook build -d ../nightly/router && cd ..
-          # cd reference && mdbook build -d ../nightly/reference && cd .. &&
-          # cd fermi && mdbook build -d ../nightly/fermi && cd ..
-
-      - name: Deploy 🚀
-        uses: JamesIves/github-pages-deploy-action@v4.5.0
-        with:
-          branch: gh-pages # The branch the action should deploy to.
-          folder: docs/nightly # The folder the action should deploy.
-          target-folder: docs
-          repository-name: dioxuslabs/docsite
-          clean: false
-          token: ${{ secrets.DEPLOY_KEY }} # let's pretend I don't need it for now

+ 0 - 38
.github/workflows/docs.yml

@@ -1,38 +0,0 @@
-name: Deploy Nightly Docs
-on:
-  push:
-    branches:
-      - master
-
-jobs:
-  deploy:
-    name: Build & Deploy
-    runs-on: ubuntu-latest
-    permissions:
-      contents: write
-
-    steps:
-      - uses: actions/checkout@v4
-      - run: sudo apt-get update
-      - run: sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev libxdo-dev
-      - uses: dtolnay/rust-toolchain@nightly
-        with:
-          toolchain: nightly-2024-02-01
-      - uses: Swatinem/rust-cache@v2
-        with:
-          cache-all-crates: "true"
-          save-if: ${{ github.ref == 'refs/heads/master' }}
-      - uses: ilammy/setup-nasm@v1
-
-      - name: cargo doc
-        run: cargo doc --no-deps --workspace --all-features
-
-      - name: Deploy
-        uses: JamesIves/github-pages-deploy-action@v4.5.0
-        with:
-          branch: gh-pages
-          folder: target/doc
-          target-folder: api-docs/nightly
-          repository-name: dioxuslabs/docsite
-          clean: false
-          token: ${{ secrets.DEPLOY_KEY }}

+ 39 - 30
.github/workflows/main.yml

@@ -1,9 +1,13 @@
+# Whenever an open PR is updated, the workflow will be triggered
+#
+# This can get expensive, so we do a lot of caching and checks to prevent unnecessary runs
+
 name: Rust CI
 
 on:
   push:
     branches:
-      - master
+      - main
     paths:
       - packages/**
       - examples/**
@@ -17,7 +21,7 @@ on:
   pull_request:
     types: [opened, synchronize, reopened, ready_for_review]
     branches:
-      - master
+      - main
     paths:
       - packages/**
       - examples/**
@@ -48,7 +52,7 @@ jobs:
       - uses: Swatinem/rust-cache@v2
         with:
           cache-all-crates: "true"
-          save-if: ${{ github.ref == 'refs/heads/master' }}
+          save-if: ${{ github.ref == 'refs/heads/main' }}
       - uses: ilammy/setup-nasm@v1
       - run: cargo check --all --examples --tests --all-features --all-targets
 
@@ -64,7 +68,7 @@ jobs:
       - uses: Swatinem/rust-cache@v2
         with:
           cache-all-crates: "true"
-          save-if: ${{ github.ref == 'refs/heads/master' }}
+          save-if: ${{ github.ref == 'refs/heads/main' }}
       - uses: ilammy/setup-nasm@v1
       - uses: davidB/rust-cargo-make@v1
       - uses: browser-actions/setup-firefox@latest
@@ -75,7 +79,6 @@ jobs:
           large-packages: false
           docker-images: false
           swap-storage: false
-
       - run: cargo make tests
 
   fmt:
@@ -91,7 +94,7 @@ jobs:
       - uses: Swatinem/rust-cache@v2
         with:
           cache-all-crates: "true"
-          save-if: ${{ github.ref == 'refs/heads/master' }}
+          save-if: ${{ github.ref == 'refs/heads/main' }}
       - run: cargo fmt --all -- --check
 
   clippy:
@@ -109,9 +112,36 @@ jobs:
       - uses: Swatinem/rust-cache@v2
         with:
           cache-all-crates: "true"
-          save-if: ${{ github.ref == 'refs/heads/master' }}
+          save-if: ${{ github.ref == 'refs/heads/main' }}
       - run: cargo clippy --workspace --examples --tests --all-features --all-targets -- -D warnings
 
+  # Only run semver checks if the PR is not a draft and does not have the breaking label
+  # Breaking PRs don't need to follow semver since they are breaking changes
+  # However, this means we won't attempt to backport them, so you should be careful about using this label, as it will
+  # likely make future backporting difficult
+  #
+  # todo: fix this so even if breaking changes have been merged, the fix can be backported
+  #
+  # This will stop working once the first breaking change has been merged, so we should really try to just backport the fix
+  # and *then* run the semver checks. Basically "would backporting this PR cause a breaking change on stable?"
+  #
+  # semver:
+  #   if: github.event.pull_request.draft == false && !contains(github.event.pull_request.labels.*.name, 'breaking')
+  #   name: Semver Check
+  #   runs-on: ubuntu-latest
+  #   steps:
+  #     - uses: actions/checkout@v4
+  #     - uses: dtolnay/rust-toolchain@stable
+  #     - uses: Swatinem/rust-cache@v2
+  #       with:
+  #         cache-all-crates: "true"
+  #         save-if: ${{ github.ref == 'refs/heads/main' }}
+  #     - name: Check semver
+  #       uses: obi1kenobi/cargo-semver-checks-action@v2
+  #       with:
+  #         manifest-path: ./Cargo.toml
+  #         exclude: "dioxus-cli, dioxus-ext"
+
   playwright:
     if: github.event.pull_request.draft == false
     name: Playwright Tests
@@ -137,7 +167,7 @@ jobs:
       - uses: Swatinem/rust-cache@v2
         with:
           cache-all-crates: "true"
-          save-if: ${{ github.ref == 'refs/heads/master' }}
+          save-if: ${{ github.ref == 'refs/heads/main' }}
 
       - name: Install dependencies
         run: npm ci
@@ -230,29 +260,8 @@ jobs:
         with:
           key: "${{ matrix.platform.target }}"
           cache-all-crates: "true"
-          save-if: ${{ github.ref == 'refs/heads/master' }}
+          save-if: ${{ github.ref == 'refs/heads/main' }}
 
       - name: test
         run: |
           ${{ env.RUST_CARGO_COMMAND }} ${{ matrix.platform.command }} ${{ matrix.platform.args }} --target ${{ matrix.platform.target }}
-
-  # Coverage is disabled until we can fix it
-  # coverage:
-  #   name: Coverage
-  #   runs-on: ubuntu-latest
-  #   container:
-  #     image: xd009642/tarpaulin:develop-nightly
-  #     options: --security-opt seccomp=unconfined
-  #   steps:
-  #     - name: Checkout repository
-  #       uses: actions/checkout@v4
-  #     - name: Generate code coverage
-  #       run: |
-  #         apt-get update &&\
-  #         apt-get install build-essential &&\
-  #         apt install libwebkit2gtk-4.0-dev libgtk-3-dev libayatana-appindicator3-dev -y &&\
-  #         cargo +nightly tarpaulin --verbose --all-features --workspace --timeout 120 --out Xml
-  #     - name: Upload to codecov.io
-  #       uses: codecov/codecov-action@v2
-  #       with:
-  #         fail_ci_if_error: false

+ 92 - 0
.github/workflows/merge.yml

@@ -0,0 +1,92 @@
+# Runs whenever a PR is merged:
+# - attempt to backports fixes
+# - upload nightly docs
+#
+# Future:
+# - upload nightly CLI builds
+# - upload nightly vscode extension
+# - upload benchmarks
+# - compute coverge
+#
+# Note that direct commits to master circumvent this workflow!
+
+name: Backport merged pull request
+on:
+  pull_request_target:
+    types: [closed]
+
+permissions:
+  contents: write # so it can comment
+  pull-requests: write # so it can create pull requests
+
+jobs:
+  # Attempt to backport a merged pull request to the latest stable release
+  backport:
+    name: Backport pull request
+    runs-on: ubuntu-latest
+
+    # Don't run on closed unmerged pull requests, or pull requests with the "breaking" label
+    if: github.event.pull_request.merged && !contains(github.event.pull_request.labels.*.name, 'breaking')
+    steps:
+      - uses: actions/checkout@v4
+      - name: Create backport pull requests
+        uses: korthout/backport-action@v2
+
+  # Upload nightly docs to the website
+  docs:
+    runs-on: ubuntu-latest
+    permissions:
+      contents: write
+    steps:
+      - uses: actions/checkout@v4
+      - run: sudo apt-get update
+      - run: sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev libxdo-dev
+      - uses: dtolnay/rust-toolchain@nightly
+        with:
+          toolchain: nightly-2024-02-01
+      - uses: Swatinem/rust-cache@v2
+        with:
+          cache-all-crates: "true"
+          save-if: ${{ github.ref == 'refs/heads/main' }}
+      - uses: ilammy/setup-nasm@v1
+
+      - name: cargo doc
+        run: cargo doc --no-deps --workspace --all-features
+
+      - name: Deploy
+        uses: JamesIves/github-pages-deploy-action@v4.5.0
+        with:
+          branch: gh-pages
+          folder: target/doc
+          target-folder: api-docs/nightly
+          repository-name: dioxuslabs/docsite
+          clean: false
+          token: ${{ secrets.DEPLOY_KEY }}
+
+# Attempt to backport a merged pull request to the latest stable release
+#
+# If the backported PR is succesfully merged
+# Any PR without the "breaking" label will be attempted to be backported to the latest stable release
+
+# Coverage is disabled until we can fix it
+# coverage:
+#   name: Coverage
+#   runs-on: ubuntu-latest
+#   container:
+#     image: xd009642/tarpaulin:develop-nightly
+#     options: --security-opt seccomp=unconfined
+#   steps:
+#     - name: Checkout repository
+#       uses: actions/checkout@v4
+#     - name: Generate code coverage
+#       run: |
+#         apt-get update &&\
+#         apt-get install build-essential &&\
+#         apt install libwebkit2gtk-4.0-dev libgtk-3-dev libayatana-appindicator3-dev -y &&\
+#         cargo +nightly tarpaulin --verbose --all-features --workspace --timeout 120 --out Xml
+#     - name: Upload to codecov.io
+#       uses: codecov/codecov-action@v2
+#       with:
+#         fail_ci_if_error: false
+
+

+ 48 - 0
.github/workflows/promote.yml

@@ -0,0 +1,48 @@
+# Promote the current main branch to a stable release.
+# This will not actually release anything, so you need to run the release workflow after this.
+#
+# IE if the current master version is 0.4.0-rc.7, this will create a PR to promote it to 0.4.0
+#
+# - update the version in the Cargo.toml to v0.4.0
+# - generate a v0.4 branch
+# - push the branch to the repository
+# - then bump 0.4.0-rc.1 to 0.5.0-rc.0
+#
+# This means main will never be a "stable" release, and we can always merge breaking changes to main
+# and backport them to the latest stable release
+#
+# This is configured to be ran manually, but could honestly just be a release workflow
+
+name: Promote main to stable branch
+on:
+  workflow_dispatch:
+
+permissions:
+  actions: write
+
+jobs:
+  promote:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+      - name: Publish the next pre-release
+        run: |
+          git config --global user.email "github-actions[bot]@users.noreply.github.com"
+          git config --global user.name "github-actions[bot]"
+
+          # go from eg 0.4.0-rc.7 to 0.4.0, committing the change
+          cargo workspaces version -y minor
+
+          # create a new branch for the release
+          RELEASE_BRANCH=$(cargo metadata --no-deps --format-version 1 | jq -r '.packages[0].version')
+          RELEASE_BRANCH=v$(echo $RELEASE_BRANCH | sed 's/\.[0-9]*$//')
+          git branch $RELEASE_BRANCH
+
+          # go from 0.4.0 to 0.5.0-rc.0
+          cargo workspaces version -y preminor --pre-id rc
+
+          # push the new branch to the repository
+          git push origin $RELEASE_BRANCH
+
+          # push the new version to the repository
+          git push origin main

+ 155 - 0
.github/workflows/publish.yml

@@ -0,0 +1,155 @@
+# Release workflow
+#
+# We parallelize builds, dump all the artifacts into a release, and then publish the release
+# This guarantees everything is properly built and cached in case anything goes wrong
+#
+# The artifacts also need to get pushed to the various places
+# - the CLI goes to the releases page for binstall
+# - the extension goes to the marketplace
+# - the docs go to the website
+#
+# We need to be aware of the channel we're releasing
+# - prerelease is master
+# - stable is whatever the latest stable release is (ie 0.4 or 0.5 or 0.6 etc)
+#
+# It's intended that this workflow is run manually, and only when we're ready to release
+
+name: Publish
+on:
+  workflow_dispatch:
+    inputs:
+      channel:
+        type: choice
+        name: "Branch to publish"
+        required: true
+        description: Choose the branch to publish.
+        options:
+          - main
+          - v0.4
+          - v0.5
+          - v0.6
+
+env:
+  # make sure we have the right version
+  # main is always a prepatch until we hit 1.0, and then this script needs to be updated
+  # note that we need to promote the prepatch to a minor bump when we actually do a release
+  # this means the version in git will always be one minor bump ahead of the actual release - basically meaning once
+  # we release a version, it's fair game to merge breaking changes to main since all semver-compatible changes will be
+  # backported automatically
+  SEMVER: ${{ github.event.inputs.channel == 'main' && 'prerelease' || 'patch' }}
+  PRERELEASE_TAG: ${{ github.event.inputs.channel == 'main' && '-pre' || '' }}
+
+jobs:
+  # First, run checks (clippy, tests, etc) and then publish the crates to crates.io
+  release-crates:
+    steps:
+      # Checkout the right branch, and the nightly stuff
+      - uses: actions/checkout@v4
+        ref: ${{ github.event.inputs.channel }}
+      - run: sudo apt-get update
+      - run: sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev libxdo-dev
+      - uses: dtolnay/rust-toolchain@nightly
+        with:
+          toolchain: nightly-2024-02-01
+      - uses: Swatinem/rust-cache@v2
+        with:
+          cache-all-crates: "true"
+      - uses: ilammy/setup-nasm@v1
+
+      - name: Free Disk Space (Ubuntu)
+        uses: jlumbroso/free-disk-space@v1.3.1
+        with: # speed things up a bit
+          large-packages: false
+          docker-images: false
+          swap-storage: false
+
+      # Just make sure clippy is happy before doing anything else
+      # Don't publish versions with clippy errors!
+      - name: Clippy
+        run: cargo clippy --workspace --all --examples --tests --all-features --all-targets -- -D warnings
+
+      # Build the docs here too before publishing, to ensure they're up to date
+      - name: cargo doc
+        run: RUSTDOCFLAGS="--cfg docsrs" cargo doc --no-deps --workspace --all-features
+
+      - name: Publish to crates.io
+        run: |
+          git config --global user.email "github-actions[bot]@users.noreply.github.com"
+          git config --global user.name "github-actions[bot]"
+          cargo workspaces version -y ${{ env.SEMVER }} --pre-id rc --no-git-commit
+
+          # todo: actually just publish!
+          # cargo workspaces publish -y ${{ github.event.inputs.semver }}
+
+      # this will be more useful when we publish the website with updated docs
+      # Build the docs.rs docs and publish them to the website under the right folder
+      # v0.4.x -> docs/0.4
+      # v0.5.x -> docs/0.5 etc
+      # main -> docs/nightly
+      # strip the v from the channel, and the .x from the end, and replace main with nightly
+      # - name: determine docs folder by channel
+      #   id: determine_docs_folder
+      #   run: echo "::set-output name=folder::$(echo ${{ github.event.inputs.channel }} | sed 's/v//g' | sed 's/\.x//g' | sed 's/main/nightly/g')"
+
+  # Build the CLI for all platforms, uploading the artifacts to our releases page
+  release-cli:
+    needs: release-crates
+    permissions:
+      contents: write
+    strategy:
+      matrix:
+        include:
+          - target: x86_64-pc-windows-msvc
+            os: windows-latest
+          - target: aaarch64-pc-windows-msvc
+            os: windows-latest
+          - target: x86_64-apple-darwin
+            os: macos-latest
+          - target: aarch64-apple-darwin
+            os: macos-latest
+          - target: x86_64-unknown-linux-gnu
+            os: ubuntu-latest
+          - target: aarch64-unknown-linux-gnu
+            os: ubuntu-latest
+    runs-on: ${{ matrix.platform.os }}
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v4
+        ref: ${{ github.event.inputs.channel }}
+
+      - name: Install stable
+        uses: dtolnay/rust-toolchain@master
+        with:
+          toolchain: "1.70.0"
+          targets: ${{ matrix.platform.target }}
+
+      - uses: ilammy/setup-nasm@v1
+
+      - name: Setup cache
+        uses: Swatinem/rust-cache@v2
+        with:
+          workspaces: packages/cli -> ../../target
+
+      - name: Free Disk Space
+        uses: jlumbroso/free-disk-space@v1.3.1
+        with: # speed things up a bit
+          large-packages: false
+          docker-images: false
+          swap-storage: false
+
+      # Todo: we want `cargo install dx` to actually just use a prebuilt binary instead of building it
+      - name: Build and upload CLI binaries
+        uses: taiki-e/upload-rust-binary-action@v1
+        with:
+          bin: dx
+          token: ${{ secrets.GITHUB_TOKEN }}
+          target: ${{ matrix.platform.target }}
+          archive: dx-${{ matrix.platform.target }}${{ env.PRERELEASE_TAG }}
+          checksum: sha256
+          manifest_path: packages/cli/Cargo.toml
+
+  # todo: these things
+  # Run benchmarks, which we'll use to display on the website
+  # release-benchmarks:
+  # Build the vscode extension, uploading the artifact to the marketplace
+  # release-extension:

+ 0 - 37
.github/workflows/wipe_cache.yml

@@ -1,37 +0,0 @@
-name: Clear cache
-
-on:
-  workflow_dispatch:
-
-permissions:
-  actions: write
-
-jobs:
-  clear-cache:
-    runs-on: ubuntu-latest
-    steps:
-      - name: Clear cache
-        uses: actions/github-script@v7
-        with:
-          github-token: ${{ secrets.cache_controller }}
-          script: |
-            console.log("About to clear")
-
-            while (true) {
-              const caches = await github.rest.actions.getActionsCacheList({
-                owner: context.repo.owner,
-                repo: context.repo.repo
-              })
-              if (caches.data.actions_caches.length === 0) {
-                break
-              }
-              for (const cache of caches.data.actions_caches) {
-                console.log(cache)
-                github.rest.actions.deleteActionsCacheById({
-                  owner: context.repo.owner,
-                  repo: context.repo.repo,
-                  cache_id: cache.id,
-                })
-              }
-            }
-            console.log("Clear completed")

+ 240 - 223
Cargo.lock

@@ -71,9 +71,9 @@ dependencies = [
 
 [[package]]
 name = "ahash"
-version = "0.8.8"
+version = "0.8.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42cd52102d3df161c77a887b608d7a4897d7cc112886a9537b738a887a03aaff"
+checksum = "d713b3834d76b85304d4d525563c1276e2e30dc97cc67bfb4585a4a29fc2c89f"
 dependencies = [
  "cfg-if",
  "const-random",
@@ -154,9 +154,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
 
 [[package]]
 name = "anstream"
-version = "0.6.11"
+version = "0.6.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5"
+checksum = "96b09b5178381e0874812a9b157f7fe84982617e48f71f4e3235482775e5b540"
 dependencies = [
  "anstyle",
  "anstyle-parse",
@@ -202,9 +202,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.79"
+version = "1.0.80"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
+checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
 
 [[package]]
 name = "anymap"
@@ -256,7 +256,7 @@ checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -278,7 +278,7 @@ dependencies = [
  "argh_shared",
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -331,7 +331,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f28243a43d821d11341ab73c80bed182dc015c514b951616cf79bd4af39af0c3"
 dependencies = [
  "concurrent-queue",
- "event-listener 5.0.0",
+ "event-listener 5.1.0",
  "event-listener-strategy 0.5.0",
  "futures-core",
  "pin-project-lite",
@@ -411,7 +411,7 @@ dependencies = [
  "futures-io",
  "futures-lite 2.2.0",
  "parking",
- "polling 3.4.0",
+ "polling 3.5.0",
  "rustix 0.38.31",
  "slab",
  "tracing",
@@ -463,7 +463,7 @@ checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -498,7 +498,7 @@ checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -616,7 +616,7 @@ dependencies = [
  "http 1.0.0",
  "http-body 1.0.0",
  "http-body-util",
- "hyper 1.1.0",
+ "hyper 1.2.0",
  "hyper-util",
  "itoa 1.0.10",
  "matchit",
@@ -737,7 +737,7 @@ dependencies = [
  "heck 0.4.1",
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -762,7 +762,7 @@ dependencies = [
  "http 1.0.0",
  "http-body 1.0.0",
  "http-body-util",
- "hyper 1.1.0",
+ "hyper 1.2.0",
  "hyper-util",
  "pin-project-lite",
  "rustls 0.21.10",
@@ -1012,7 +1012,7 @@ dependencies = [
  "proc-macro-crate 3.1.0",
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
  "syn_derive",
 ]
 
@@ -1083,9 +1083,9 @@ checksum = "38d17f4d6e4dc36d1a02fbedc2753a096848e7c1b0772f7654eab8e2c927dd53"
 
 [[package]]
 name = "bumpalo"
-version = "3.15.0"
+version = "3.15.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d32a994c2b3ca201d9b263612a374263f05e7adde37c4707f693dcd375076d1f"
+checksum = "a3b1be7772ee4501dba05acbe66bb1e8760f6a6c474a36035631638e4415f130"
 
 [[package]]
 name = "bytecheck"
@@ -1332,11 +1332,10 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
 
 [[package]]
 name = "cc"
-version = "1.0.83"
+version = "1.0.86"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
+checksum = "7f9fa1897e4325be0d68d48df6aa1a71ac2ed4d27723887e7754192705350730"
 dependencies = [
- "jobserver",
  "libc",
 ]
 
@@ -1400,7 +1399,7 @@ dependencies = [
  "num-traits",
  "serde",
  "wasm-bindgen",
- "windows-targets 0.52.0",
+ "windows-targets 0.52.3",
 ]
 
 [[package]]
@@ -1482,7 +1481,7 @@ dependencies = [
  "heck 0.4.1",
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -2004,7 +2003,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
 dependencies = [
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -2035,7 +2034,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "30d2b3721e861707777e3195b0158f950ae6dc4a27e4d02ff9f67e3eb3de199e"
 dependencies = [
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -2087,7 +2086,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "strsim",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -2098,7 +2097,7 @@ checksum = "c5a91391accf613803c2a9bf9abccdbaa07c54b4244a5b64883f9c3c137c86be"
 dependencies = [
  "darling_core",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -2207,7 +2206,7 @@ dependencies = [
 
 [[package]]
 name = "dioxus"
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 dependencies = [
  "criterion 0.3.6",
  "dioxus-config-macro",
@@ -2236,7 +2235,7 @@ dependencies = [
 
 [[package]]
 name = "dioxus-autofmt"
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 dependencies = [
  "dioxus-rsx",
  "prettier-please",
@@ -2244,12 +2243,12 @@ dependencies = [
  "proc-macro2",
  "quote",
  "serde",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
 name = "dioxus-check"
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 dependencies = [
  "indoc",
  "owo-colors",
@@ -2261,7 +2260,7 @@ dependencies = [
 
 [[package]]
 name = "dioxus-cli"
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 dependencies = [
  "anyhow",
  "atty",
@@ -2289,7 +2288,7 @@ dependencies = [
  "futures-util",
  "headers 0.3.9",
  "html_parser",
- "hyper 1.1.0",
+ "hyper 1.2.0",
  "hyper-rustls 0.26.0",
  "hyper-util",
  "ignore",
@@ -2308,7 +2307,7 @@ dependencies = [
  "serde",
  "serde_json",
  "subprocess",
- "syn 2.0.49",
+ "syn 2.0.50",
  "tar",
  "tauri-bundler",
  "tempfile",
@@ -2325,7 +2324,7 @@ dependencies = [
 
 [[package]]
 name = "dioxus-cli-config"
-version = "0.4.1"
+version = "0.5.0-alpha.0"
 dependencies = [
  "cargo_toml 0.16.3",
  "clap 4.4.18",
@@ -2340,7 +2339,7 @@ dependencies = [
 
 [[package]]
 name = "dioxus-config-macro"
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -2348,7 +2347,7 @@ dependencies = [
 
 [[package]]
 name = "dioxus-core"
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 dependencies = [
  "dioxus",
  "dioxus-ssr",
@@ -2362,11 +2361,13 @@ dependencies = [
  "slab",
  "tokio",
  "tracing",
+ "tracing-fluent-assertions",
+ "tracing-subscriber",
 ]
 
 [[package]]
 name = "dioxus-core-macro"
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 dependencies = [
  "constcat",
  "convert_case 0.6.0",
@@ -2376,7 +2377,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "rustversion",
- "syn 2.0.49",
+ "syn 2.0.50",
  "trybuild",
 ]
 
@@ -2388,7 +2389,7 @@ checksum = "2ea539174bb236e0e7dc9c12b19b88eae3cb574dedbd0252a2d43ea7e6de13e2"
 
 [[package]]
 name = "dioxus-desktop"
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 dependencies = [
  "async-trait",
  "core-foundation",
@@ -2426,7 +2427,7 @@ dependencies = [
 
 [[package]]
 name = "dioxus-examples"
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 dependencies = [
  "dioxus",
  "dioxus-ssr",
@@ -2445,7 +2446,7 @@ dependencies = [
 
 [[package]]
 name = "dioxus-ext"
-version = "0.1.0"
+version = "0.5.0-alpha.0"
 dependencies = [
  "dioxus-autofmt",
  "html_parser",
@@ -2455,7 +2456,7 @@ dependencies = [
 
 [[package]]
 name = "dioxus-fullstack"
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 dependencies = [
  "anymap 0.12.1",
  "async-trait",
@@ -2473,7 +2474,7 @@ dependencies = [
  "dioxus_server_macro",
  "futures-util",
  "http 1.0.0",
- "hyper 1.1.0",
+ "hyper 1.2.0",
  "once_cell",
  "pin-project",
  "serde",
@@ -2493,7 +2494,7 @@ dependencies = [
 
 [[package]]
 name = "dioxus-hooks"
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 dependencies = [
  "dioxus",
  "dioxus-core",
@@ -2510,7 +2511,7 @@ dependencies = [
 
 [[package]]
 name = "dioxus-hot-reload"
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 dependencies = [
  "chrono",
  "dioxus-core",
@@ -2527,7 +2528,7 @@ dependencies = [
 
 [[package]]
 name = "dioxus-html"
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 dependencies = [
  "async-trait",
  "dioxus-core",
@@ -2550,18 +2551,18 @@ dependencies = [
 
 [[package]]
 name = "dioxus-html-internal-macro"
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 dependencies = [
  "convert_case 0.6.0",
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
  "trybuild",
 ]
 
 [[package]]
 name = "dioxus-interpreter-js"
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 dependencies = [
  "dioxus-core",
  "dioxus-html",
@@ -2575,7 +2576,7 @@ dependencies = [
 
 [[package]]
 name = "dioxus-lib"
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 dependencies = [
  "dioxus-config-macro",
  "dioxus-core",
@@ -2588,7 +2589,7 @@ dependencies = [
 
 [[package]]
 name = "dioxus-liveview"
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 dependencies = [
  "axum",
  "dioxus",
@@ -2616,14 +2617,14 @@ dependencies = [
 
 [[package]]
 name = "dioxus-mobile"
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 dependencies = [
  "dioxus-desktop",
 ]
 
 [[package]]
 name = "dioxus-native-core"
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 dependencies = [
  "anymap 1.0.0-beta.2",
  "dashmap",
@@ -2644,7 +2645,7 @@ dependencies = [
 
 [[package]]
 name = "dioxus-native-core-macro"
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 dependencies = [
  "anymap 0.12.1",
  "dioxus",
@@ -2652,7 +2653,7 @@ dependencies = [
  "quote",
  "rustc-hash",
  "smallvec",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -2696,7 +2697,7 @@ dependencies = [
 
 [[package]]
 name = "dioxus-router"
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 dependencies = [
  "axum",
  "console_error_panic_hook",
@@ -2725,17 +2726,17 @@ dependencies = [
 
 [[package]]
 name = "dioxus-router-macro"
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 dependencies = [
  "proc-macro2",
  "quote",
  "slab",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
 name = "dioxus-rsx"
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 dependencies = [
  "dioxus-core",
  "internment",
@@ -2743,13 +2744,13 @@ dependencies = [
  "proc-macro2",
  "quote",
  "serde",
- "syn 2.0.49",
+ "syn 2.0.50",
  "tracing",
 ]
 
 [[package]]
 name = "dioxus-signals"
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 dependencies = [
  "dioxus",
  "dioxus-core",
@@ -2769,7 +2770,7 @@ dependencies = [
 
 [[package]]
 name = "dioxus-ssr"
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 dependencies = [
  "anyhow",
  "argh",
@@ -2803,7 +2804,7 @@ dependencies = [
 
 [[package]]
 name = "dioxus-tui"
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 dependencies = [
  "criterion 0.3.6",
  "crossterm 0.26.1",
@@ -2821,7 +2822,7 @@ dependencies = [
 
 [[package]]
 name = "dioxus-web"
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 dependencies = [
  "async-trait",
  "console_error_panic_hook",
@@ -2851,13 +2852,13 @@ dependencies = [
 
 [[package]]
 name = "dioxus_server_macro"
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 dependencies = [
  "convert_case 0.6.0",
  "proc-macro2",
  "quote",
  "server_fn_macro",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -2980,7 +2981,7 @@ dependencies = [
  "heck 0.4.1",
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -3001,7 +3002,7 @@ checksum = "5c785274071b1b420972453b306eeca06acf4633829db4223b58a2a8c5953bc4"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -3022,7 +3023,7 @@ dependencies = [
  "darling",
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -3105,9 +3106,9 @@ dependencies = [
 
 [[package]]
 name = "event-listener"
-version = "5.0.0"
+version = "5.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b72557800024fabbaa2449dd4bf24e37b93702d457a4d4f2b0dd1f0f039f20c1"
+checksum = "b7ad6fd685ce13acd6d9541a30f6db6567a7a24c9ffd4ba2955d29e3f22c8b27"
 dependencies = [
  "concurrent-queue",
  "parking",
@@ -3130,7 +3131,7 @@ version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "feedafcaa9b749175d5ac357452a9d41ea2911da598fde46ce1fe02c37751291"
 dependencies = [
- "event-listener 5.0.0",
+ "event-listener 5.1.0",
  "pin-project-lite",
 ]
 
@@ -3162,7 +3163,7 @@ checksum = "ce8cd46a041ad005ab9c71263f9a0ff5b529eac0fe4cc9b4a20f4f0765d8cf4b"
 dependencies = [
  "execute-command-tokens",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -3330,7 +3331,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -3513,7 +3514,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -3656,7 +3657,7 @@ dependencies = [
 
 [[package]]
 name = "generational-box"
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 dependencies = [
  "criterion 0.3.6",
  "parking_lot",
@@ -4044,7 +4045,7 @@ dependencies = [
  "proc-macro-error",
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -4356,7 +4357,7 @@ dependencies = [
  "proc-macro-error",
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -4442,7 +4443,7 @@ version = "0.13.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
 dependencies = [
- "ahash 0.8.8",
+ "ahash 0.8.9",
  "bumpalo",
 ]
 
@@ -4452,7 +4453,7 @@ version = "0.14.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
 dependencies = [
- "ahash 0.8.8",
+ "ahash 0.8.9",
  "allocator-api2",
 ]
 
@@ -4731,9 +4732,9 @@ dependencies = [
 
 [[package]]
 name = "hyper"
-version = "1.1.0"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb5aa53871fc917b1a9ed87b683a5d86db645e23acb32c2e0785a353e522fb75"
+checksum = "186548d73ac615b32a73aafe38fb4f56c0d340e110e5a200bcadbaf2e199263a"
 dependencies = [
  "bytes",
  "futures-channel",
@@ -4745,6 +4746,7 @@ dependencies = [
  "httpdate",
  "itoa 1.0.10",
  "pin-project-lite",
+ "smallvec",
  "tokio",
  "want",
 ]
@@ -4771,7 +4773,7 @@ checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c"
 dependencies = [
  "futures-util",
  "http 1.0.0",
- "hyper 1.1.0",
+ "hyper 1.2.0",
  "hyper-util",
  "log",
  "rustls 0.22.2",
@@ -4806,7 +4808,7 @@ dependencies = [
  "futures-util",
  "http 1.0.0",
  "http-body 1.0.0",
- "hyper 1.1.0",
+ "hyper 1.2.0",
  "pin-project-lite",
  "socket2 0.5.5",
  "tokio",
@@ -5041,7 +5043,7 @@ checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -5244,15 +5246,6 @@ version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
 
-[[package]]
-name = "jobserver"
-version = "0.1.28"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6"
-dependencies = [
- "libc",
-]
-
 [[package]]
 name = "jpeg-decoder"
 version = "0.3.1"
@@ -5475,9 +5468,9 @@ dependencies = [
 
 [[package]]
 name = "libwebp-sys"
-version = "0.9.4"
+version = "0.9.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e0df0a0f9444d52aee6335cd724d21a2ee3285f646291799a72be518ec8ee3c"
+checksum = "829b6b604f31ed6d2bccbac841fe0788de93dbd87e4eb1ba2c4adfe8c012a838"
 dependencies = [
  "cc",
  "glob",
@@ -5520,7 +5513,7 @@ version = "1.0.0-alpha.53"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4ae8ba2b1b450cefc6a7a6ee93868992f56f662869b90404de2a7319da18640f"
 dependencies = [
- "ahash 0.8.8",
+ "ahash 0.8.9",
  "bitflags 2.4.2",
  "const-str",
  "cssparser 0.33.0",
@@ -5611,7 +5604,7 @@ checksum = "fc2fb41a9bb4257a3803154bdf7e2df7d45197d1941c9b1a90ad815231630721"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -5727,16 +5720,18 @@ dependencies = [
 
 [[package]]
 name = "manganis"
-version = "0.1.0"
-source = "git+https://github.com/DioxusLabs/collect-assets?rev=f982698#f982698027fc27d22acfb4121fba389ec125d538"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d11b87b5222a0eb4c7b1e7a49cc78922aa82a7fa5aa614e07ace55ed74fcdf67"
 dependencies = [
  "manganis-macro",
 ]
 
 [[package]]
 name = "manganis-cli-support"
-version = "0.1.0"
-source = "git+https://github.com/DioxusLabs/collect-assets?rev=f982698#f982698027fc27d22acfb4121fba389ec125d538"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d9c40a20048742dfbb793fb93498640e128543bcf92588b4c3b25451957522d"
 dependencies = [
  "anyhow",
  "cargo-lock 9.0.0",
@@ -5761,8 +5756,9 @@ dependencies = [
 
 [[package]]
 name = "manganis-common"
-version = "0.1.0"
-source = "git+https://github.com/DioxusLabs/collect-assets?rev=f982698#f982698027fc27d22acfb4121fba389ec125d538"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "84166560d60366c4b4fe12e204f2fca78fe594382e13c02d75fab6e0d8f40184"
 dependencies = [
  "anyhow",
  "base64",
@@ -5776,15 +5772,14 @@ dependencies = [
 
 [[package]]
 name = "manganis-macro"
-version = "0.0.1"
-source = "git+https://github.com/DioxusLabs/collect-assets?rev=f982698#f982698027fc27d22acfb4121fba389ec125d538"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b78150e016312c51841521a9dc7fb5ae994c163a325eb4c2aa0186efce9532e"
 dependencies = [
- "base64",
- "manganis-cli-support",
  "manganis-common",
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -6002,9 +5997,9 @@ dependencies = [
 
 [[package]]
 name = "muda"
-version = "0.11.4"
+version = "0.11.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e406691fa7749604bbc7964bde28a300572d52621bb84540f6907c0f8fe08737"
+checksum = "4c47e7625990fc1af2226ea4f34fb2412b03c12639fcb91868581eb3a6893453"
 dependencies = [
  "cocoa",
  "crossbeam-channel",
@@ -6173,11 +6168,11 @@ checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8"
 
 [[package]]
 name = "normpath"
-version = "1.1.1"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec60c60a693226186f5d6edf073232bfb6464ed97eb22cf3b01c1e8198fd97f5"
+checksum = "5831952a9476f2fed74b77d74182fa5ddc4d21c72ec45a333b250e3ed0272804"
 dependencies = [
- "windows-sys 0.48.0",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
@@ -6262,7 +6257,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -6432,9 +6427,9 @@ dependencies = [
 
 [[package]]
 name = "openssl"
-version = "0.10.63"
+version = "0.10.64"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "15c9d69dd87a29568d4d017cfe8ec518706046a05184e5aea92d0af890b803c8"
+checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f"
 dependencies = [
  "bitflags 2.4.2",
  "cfg-if",
@@ -6453,7 +6448,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -6473,9 +6468,9 @@ dependencies = [
 
 [[package]]
 name = "openssl-sys"
-version = "0.9.99"
+version = "0.9.101"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22e1bf214306098e4832460f797824c05d25aacdf896f64a985fb0fd992454ae"
+checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff"
 dependencies = [
  "cc",
  "libc",
@@ -6736,7 +6731,7 @@ dependencies = [
  "pest_meta",
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -6864,7 +6859,7 @@ dependencies = [
  "phf_shared 0.11.2",
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -6911,7 +6906,7 @@ checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -6966,7 +6961,7 @@ checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
 
 [[package]]
 name = "plasmo"
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 dependencies = [
  "anyhow",
  "anymap 1.0.0-beta.2",
@@ -7030,9 +7025,9 @@ dependencies = [
 
 [[package]]
 name = "png"
-version = "0.17.12"
+version = "0.17.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78c2378060fb13acff3ba0325b83442c1d2c44fbb76df481160ddc1687cce160"
+checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1"
 dependencies = [
  "bitflags 1.3.2",
  "crc32fast",
@@ -7059,9 +7054,9 @@ dependencies = [
 
 [[package]]
 name = "polling"
-version = "3.4.0"
+version = "3.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30054e72317ab98eddd8561db0f6524df3367636884b7b21b703e4b280a84a14"
+checksum = "24f040dee2588b4963afb4e420540439d126f73fdacf4a9c486a96d840bac3c9"
 dependencies = [
  "cfg-if",
  "concurrent-queue",
@@ -7114,7 +7109,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "22020dfcf177fcc7bf5deaf7440af371400c67c0de14c399938d8ed4fb4645d3"
 dependencies = [
  "proc-macro2",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -7144,7 +7139,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5"
 dependencies = [
  "proc-macro2",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -7222,21 +7217,21 @@ checksum = "794b5bf8e2d19b53dcdcec3e4bba628e20f5b6062503ba89281fa7037dd7bbcf"
 
 [[package]]
 name = "profiling"
-version = "1.0.14"
+version = "1.0.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f0f7f43585c34e4fdd7497d746bc32e14458cf11c69341cc0587b1d825dde42"
+checksum = "43d84d1d7a6ac92673717f9f6d1518374ef257669c24ebc5ac25d5033828be58"
 dependencies = [
  "profiling-procmacros",
 ]
 
 [[package]]
 name = "profiling-procmacros"
-version = "1.0.14"
+version = "1.0.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce97fecd27bc49296e5e20518b5a1bb54a14f7d5fe6228bc9686ee2a74915cc8"
+checksum = "8021cf59c8ec9c432cfc2526ac6b8aa508ecaf29cd415f271b8406c1b851c3fd"
 dependencies = [
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -7711,7 +7706,7 @@ version = "1.16.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e3625f343d89990133d013e39c46e350915178cf94f1bec9f49b0cbef98a3e3c"
 dependencies = [
- "ahash 0.8.8",
+ "ahash 0.8.9",
  "bitflags 2.4.2",
  "instant",
  "num-traits",
@@ -7729,21 +7724,22 @@ checksum = "853977598f084a492323fe2f7896b4100a86284ee8473612de60021ea341310f"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
 name = "ring"
-version = "0.17.7"
+version = "0.17.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74"
+checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
 dependencies = [
  "cc",
+ "cfg-if",
  "getrandom 0.2.12",
  "libc",
  "spin 0.9.8",
  "untrusted",
- "windows-sys 0.48.0",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
@@ -7816,7 +7812,7 @@ dependencies = [
 
 [[package]]
 name = "rsx-rosetta"
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 dependencies = [
  "convert_case 0.5.0",
  "dioxus-autofmt",
@@ -7826,7 +7822,7 @@ dependencies = [
  "pretty_assertions",
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -8008,9 +8004,9 @@ checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
 
 [[package]]
 name = "ryu"
-version = "1.0.16"
+version = "1.0.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
+checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
 
 [[package]]
 name = "safemem"
@@ -8119,9 +8115,9 @@ dependencies = [
 
 [[package]]
 name = "semver"
-version = "1.0.21"
+version = "1.0.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0"
+checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
 dependencies = [
  "serde",
 ]
@@ -8143,9 +8139,9 @@ checksum = "f97841a747eef040fcd2e7b3b9a220a7205926e60488e673d9e4926d27772ce5"
 
 [[package]]
 name = "serde"
-version = "1.0.196"
+version = "1.0.197"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32"
+checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
 dependencies = [
  "serde_derive",
 ]
@@ -8183,20 +8179,20 @@ dependencies = [
 
 [[package]]
 name = "serde_derive"
-version = "1.0.196"
+version = "1.0.197"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67"
+checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
 name = "serde_json"
-version = "1.0.113"
+version = "1.0.114"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79"
+checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0"
 dependencies = [
  "itoa 1.0.10",
  "ryu",
@@ -8242,7 +8238,7 @@ checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -8293,14 +8289,14 @@ dependencies = [
  "darling",
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
 name = "server_fn"
-version = "0.6.5"
+version = "0.6.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97fab54d9dd2d7e9eba4efccac41d2ec3e7c6e9973d14c0486d662a32662320c"
+checksum = "dcbe027777b6bcb1fff76eb2ff3596cd68dbc52e5b703a0264db31fb6eb870ba"
 dependencies = [
  "axum",
  "bytes",
@@ -8310,7 +8306,7 @@ dependencies = [
  "gloo-net 0.5.0",
  "http 1.0.0",
  "http-body-util",
- "hyper 1.1.0",
+ "hyper 1.2.0",
  "inventory",
  "js-sys",
  "once_cell",
@@ -8333,26 +8329,26 @@ dependencies = [
 
 [[package]]
 name = "server_fn_macro"
-version = "0.6.5"
+version = "0.6.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3be6011b586a0665546b7ced372b0be690d9e005d3f8524795da2843274d7720"
+checksum = "51c788951450843a3ed4b9df0268e48ea00be44b8a5f453e299ef4abb5c86b8c"
 dependencies = [
  "const_format",
  "convert_case 0.6.0",
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
  "xxhash-rust",
 ]
 
 [[package]]
 name = "server_fn_macro_default"
-version = "0.6.5"
+version = "0.6.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "752ed78ec49132d154b922cf5ab6485680cab039a75740c48ea2db621ad481da"
+checksum = "89732cbf095803f0a23dff6a9d2f469049d48affdaa80edee0d826c986330ced"
 dependencies = [
  "server_fn_macro",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -8530,12 +8526,22 @@ dependencies = [
 
 [[package]]
 name = "sledgehammer_bindgen"
-version = "0.3.1"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa1ca40134578bf7cf17973defcd4eb8d7d2adf7868b29892481722957bd543e"
+dependencies = [
+ "sledgehammer_bindgen_macro",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "sledgehammer_bindgen_macro"
+version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9298e863f0143b89972299110a7fa3e2fc08c412341d588c497bae38409f9e68"
+checksum = "04559ded3de5c62f08457cadcb6c44649c4d90e72fdc0804c6c30ce1bc526304"
 dependencies = [
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -8685,7 +8691,7 @@ version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d84b0a3c3739e220d94b3239fd69fb1f74bc36e16643423bd99de3b43c21bfbd"
 dependencies = [
- "ahash 0.8.8",
+ "ahash 0.8.9",
  "atoi",
  "bigdecimal",
  "bit-vec",
@@ -8977,7 +8983,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "rustversion",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -9019,9 +9025,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "2.0.49"
+version = "2.0.50"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "915aea9e586f80826ee59f8453c1101f9d1c4b3964cd2460185ee8e299ada496"
+checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -9037,7 +9043,7 @@ dependencies = [
  "proc-macro-error",
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -9164,9 +9170,9 @@ dependencies = [
 
 [[package]]
 name = "target-lexicon"
-version = "0.12.13"
+version = "0.12.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "69758bda2e78f098e4ccb393021a0963bb3442eac05f135c30f61b7370bbafae"
+checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f"
 
 [[package]]
 name = "tauri-bundler"
@@ -9222,9 +9228,9 @@ dependencies = [
 
 [[package]]
 name = "tauri-utils"
-version = "1.5.2"
+version = "1.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ece74810b1d3d44f29f732a7ae09a63183d63949bbdd59c61f8ed2a1b70150db"
+checksum = "75ad0bbb31fccd1f4c56275d0a5c3abdf1f59999f72cb4ef8b79b4ed42082a21"
 dependencies = [
  "ctor",
  "dunce",
@@ -9322,14 +9328,14 @@ checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
 name = "thread_local"
-version = "1.1.7"
+version = "1.1.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152"
+checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
 dependencies = [
  "cfg-if",
  "once_cell",
@@ -9446,7 +9452,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -9608,7 +9614,7 @@ dependencies = [
  "serde",
  "serde_spanned",
  "toml_datetime",
- "winnow 0.6.1",
+ "winnow 0.6.2",
 ]
 
 [[package]]
@@ -9690,7 +9696,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -9703,6 +9709,17 @@ dependencies = [
  "valuable",
 ]
 
+[[package]]
+name = "tracing-fluent-assertions"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12de1a8c6bcfee614305e836308b596bbac831137a04c61f7e5b0b0bf2cfeaf6"
+dependencies = [
+ "tracing",
+ "tracing-core",
+ "tracing-subscriber",
+]
+
 [[package]]
 name = "tracing-futures"
 version = "0.2.5"
@@ -9897,9 +9914,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
 
 [[package]]
 name = "unicode-normalization"
-version = "0.1.22"
+version = "0.1.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
+checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5"
 dependencies = [
  "tinyvec",
 ]
@@ -10137,7 +10154,7 @@ dependencies = [
  "once_cell",
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
  "wasm-bindgen-shared",
 ]
 
@@ -10203,7 +10220,7 @@ checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
@@ -10246,7 +10263,7 @@ checksum = "a5211b7550606857312bba1d978a8ec75692eae187becc5e680444fffc5e6f89"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -10438,7 +10455,7 @@ checksum = "ac1345798ecd8122468840bcdf1b95e5dc6d2206c5e4b0eafa078d061f59c9bc"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -10522,7 +10539,7 @@ dependencies = [
  "windows-core",
  "windows-implement",
  "windows-interface",
- "windows-targets 0.52.0",
+ "windows-targets 0.52.3",
 ]
 
 [[package]]
@@ -10531,7 +10548,7 @@ version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
 dependencies = [
- "windows-targets 0.52.0",
+ "windows-targets 0.52.3",
 ]
 
 [[package]]
@@ -10542,7 +10559,7 @@ checksum = "12168c33176773b86799be25e2a2ba07c7aab9968b37541f1094dbd7a60c8946"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -10553,7 +10570,7 @@ checksum = "9d8dc32e0095a7eeccebd0e3f09e9509365ecb3fc6ac4d6f5f14a3f6392942d1"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]
@@ -10580,7 +10597,7 @@ version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
 dependencies = [
- "windows-targets 0.52.0",
+ "windows-targets 0.52.3",
 ]
 
 [[package]]
@@ -10615,17 +10632,17 @@ dependencies = [
 
 [[package]]
 name = "windows-targets"
-version = "0.52.0"
+version = "0.52.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
+checksum = "d380ba1dc7187569a8a9e91ed34b8ccfc33123bbacb8c0aed2d1ad7f3ef2dc5f"
 dependencies = [
- "windows_aarch64_gnullvm 0.52.0",
- "windows_aarch64_msvc 0.52.0",
- "windows_i686_gnu 0.52.0",
- "windows_i686_msvc 0.52.0",
- "windows_x86_64_gnu 0.52.0",
- "windows_x86_64_gnullvm 0.52.0",
- "windows_x86_64_msvc 0.52.0",
+ "windows_aarch64_gnullvm 0.52.3",
+ "windows_aarch64_msvc 0.52.3",
+ "windows_i686_gnu 0.52.3",
+ "windows_i686_msvc 0.52.3",
+ "windows_x86_64_gnu 0.52.3",
+ "windows_x86_64_gnullvm 0.52.3",
+ "windows_x86_64_msvc 0.52.3",
 ]
 
 [[package]]
@@ -10634,7 +10651,7 @@ version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "75aa004c988e080ad34aff5739c39d0312f4684699d6d71fc8a198d057b8b9b4"
 dependencies = [
- "windows-targets 0.52.0",
+ "windows-targets 0.52.3",
 ]
 
 [[package]]
@@ -10651,9 +10668,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.52.0"
+version = "0.52.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
+checksum = "68e5dcfb9413f53afd9c8f86e56a7b4d86d9a2fa26090ea2dc9e40fba56c6ec6"
 
 [[package]]
 name = "windows_aarch64_msvc"
@@ -10669,9 +10686,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.52.0"
+version = "0.52.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
+checksum = "8dab469ebbc45798319e69eebf92308e541ce46760b49b18c6b3fe5e8965b30f"
 
 [[package]]
 name = "windows_i686_gnu"
@@ -10687,9 +10704,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.52.0"
+version = "0.52.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
+checksum = "2a4e9b6a7cac734a8b4138a4e1044eac3404d8326b6c0f939276560687a033fb"
 
 [[package]]
 name = "windows_i686_msvc"
@@ -10705,9 +10722,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.52.0"
+version = "0.52.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
+checksum = "28b0ec9c422ca95ff34a78755cfa6ad4a51371da2a5ace67500cf7ca5f232c58"
 
 [[package]]
 name = "windows_x86_64_gnu"
@@ -10723,9 +10740,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.52.0"
+version = "0.52.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
+checksum = "704131571ba93e89d7cd43482277d6632589b18ecf4468f591fbae0a8b101614"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
@@ -10741,9 +10758,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.52.0"
+version = "0.52.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
+checksum = "42079295511643151e98d61c38c0acc444e52dd42ab456f7ccfd5152e8ecf21c"
 
 [[package]]
 name = "windows_x86_64_msvc"
@@ -10759,9 +10776,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.52.0"
+version = "0.52.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
+checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6"
 
 [[package]]
 name = "winnow"
@@ -10774,9 +10791,9 @@ dependencies = [
 
 [[package]]
 name = "winnow"
-version = "0.6.1"
+version = "0.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d90f4e0f530c4c69f62b80d839e9ef3855edc9cba471a160c4d692deed62b401"
+checksum = "7a4191c47f15cc3ec71fcb4913cb83d58def65dd3787610213c649283b5ce178"
 dependencies = [
  "memchr",
 ]
@@ -10889,9 +10906,9 @@ dependencies = [
 
 [[package]]
 name = "xxhash-rust"
-version = "0.8.8"
+version = "0.8.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53be06678ed9e83edb1745eb72efc0bbcd7b5c3c35711a860906aed827a13d61"
+checksum = "927da81e25be1e1a2901d59b81b37dd2efd1fc9c9345a55007f09bf5a2d3ee03"
 
 [[package]]
 name = "yansi"
@@ -10982,7 +10999,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.49",
+ "syn 2.0.50",
 ]
 
 [[package]]

+ 37 - 36
Cargo.toml

@@ -51,40 +51,41 @@ members = [
 exclude = ["examples/mobile_demo", "examples/openid_connect_demo",]
 
 [workspace.package]
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 
 # dependencies that are shared across packages
 [workspace.dependencies]
-dioxus = { path = "packages/dioxus", version = "0.4.0" }
-dioxus-lib = { path = "packages/dioxus-lib", version = "0.4.0" }
-dioxus-core = { path = "packages/core", version = "0.4.2" }
-dioxus-core-macro = { path = "packages/core-macro", version = "0.4.0" }
-dioxus-config-macro = { path = "packages/config-macro", version = "0.4.0" }
-dioxus-router = { path = "packages/router", version = "0.4.1"  }
-dioxus-router-macro = { path = "packages/router-macro", version = "0.4.1" }
-dioxus-html = { path = "packages/html", version = "0.4.0"  }
-dioxus-html-internal-macro = { path = "packages/html-internal-macro", version = "0.4.0"  }
-dioxus-hooks = { path = "packages/hooks", version = "0.4.0" }
-dioxus-web = { path = "packages/web", version = "0.4.0" }
-dioxus-ssr = { path = "packages/ssr", version = "0.4.0", default-features = false }
-dioxus-desktop = { path = "packages/desktop", version = "0.4.0" }
-dioxus-mobile = { path = "packages/mobile", version = "0.4.0"  }
-dioxus-interpreter-js = { path = "packages/interpreter", version = "0.4.0" }
-dioxus-liveview = { path = "packages/liveview", version = "0.4.0"  }
-dioxus-autofmt = { path = "packages/autofmt", version = "0.4.0"  }
-dioxus-check = { path = "packages/check", version = "0.4.0"  }
-dioxus-rsx = { path = "packages/rsx", version = "0.4.0"  }
-dioxus-tui = { path = "packages/dioxus-tui", version = "0.4.0"  }
-plasmo = { path = "packages/plasmo", version = "0.4.0" }
-dioxus-native-core = { path = "packages/native-core", version = "0.4.0" }
-dioxus-native-core-macro = { path = "packages/native-core-macro", version = "0.4.0" }
-rsx-rosetta = { path = "packages/rsx-rosetta", version = "0.4.0" }
-dioxus-signals = { path = "packages/signals" }
-dioxus-cli-config = { path = "packages/cli-config", version = "0.4.1" }
-generational-box = { path = "packages/generational-box", version = "0.4.3" }
-dioxus-hot-reload = { path = "packages/hot-reload", version = "0.4.0" }
-dioxus-fullstack = { path = "packages/fullstack", version = "0.4.1" }
-dioxus_server_macro = { path = "packages/server-macro", version = "0.4.1" }
+dioxus = { path = "packages/dioxus", version = "0.5.0-alpha.0" }
+dioxus-lib = { path = "packages/dioxus-lib", version = "0.5.0-alpha.0" }
+dioxus-core = { path = "packages/core", version = "0.5.0-alpha.0" }
+dioxus-core-macro = { path = "packages/core-macro", version = "0.5.0-alpha.0" }
+dioxus-config-macro = { path = "packages/config-macro", version = "0.5.0-alpha.0" }
+dioxus-router = { path = "packages/router", version = "0.5.0-alpha.0"  }
+dioxus-router-macro = { path = "packages/router-macro", version = "0.5.0-alpha.0" }
+dioxus-html = { path = "packages/html", version = "0.5.0-alpha.0"  }
+dioxus-html-internal-macro = { path = "packages/html-internal-macro", version = "0.5.0-alpha.0"  }
+dioxus-hooks = { path = "packages/hooks", version = "0.5.0-alpha.0" }
+dioxus-web = { path = "packages/web", version = "0.5.0-alpha.0" }
+dioxus-ssr = { path = "packages/ssr", version = "0.5.0-alpha.0", default-features = false }
+dioxus-desktop = { path = "packages/desktop", version = "0.5.0-alpha.0" }
+dioxus-mobile = { path = "packages/mobile", version = "0.5.0-alpha.0"  }
+dioxus-interpreter-js = { path = "packages/interpreter", version = "0.5.0-alpha.0" }
+dioxus-liveview = { path = "packages/liveview", version = "0.5.0-alpha.0"  }
+dioxus-autofmt = { path = "packages/autofmt", version = "0.5.0-alpha.0"  }
+dioxus-check = { path = "packages/check", version = "0.5.0-alpha.0"  }
+dioxus-rsx = { path = "packages/rsx", version = "0.5.0-alpha.0"  }
+dioxus-tui = { path = "packages/dioxus-tui", version = "0.5.0-alpha.0"  }
+plasmo = { path = "packages/plasmo", version = "0.5.0-alpha.0" }
+dioxus-native-core = { path = "packages/native-core", version = "0.5.0-alpha.0" }
+dioxus-native-core-macro = { path = "packages/native-core-macro", version = "0.5.0-alpha.0" }
+rsx-rosetta = { path = "packages/rsx-rosetta", version = "0.5.0-alpha.0" }
+dioxus-signals = { path = "packages/signals", version = "0.5.0-alpha.0" }
+dioxus-cli-config = { path = "packages/cli-config", version = "0.5.0-alpha.0" }
+generational-box = { path = "packages/generational-box", version = "0.5.0-alpha.0" }
+dioxus-hot-reload = { path = "packages/hot-reload", version = "0.5.0-alpha.0" }
+dioxus-fullstack = { path = "packages/fullstack", version = "0.5.0-alpha.0" }
+dioxus_server_macro = { path = "packages/server-macro", version = "0.5.0-alpha.0", default-features = false}
+dioxus-ext = { path = "packages/extension", version = "0.4.0" }
 tracing = "0.1.37"
 tracing-futures = "0.2.5"
 toml = "0.8"
@@ -99,16 +100,16 @@ thiserror = "1.0.40"
 prettyplease = { package = "prettier-please", version = "0.2", features = [
     "verbatim",
 ] }
-manganis-cli-support = { git = "https://github.com/DioxusLabs/collect-assets", rev = "f982698", features = [
+manganis-cli-support = { version = "0.1.0", features = [
     "webp",
     "html",
 ] }
-manganis = { git = "https://github.com/DioxusLabs/collect-assets", rev = "f982698" }
+manganis = { version = "0.1.0" }
 
 lru = "0.12.2"
 async-trait = "0.1.77"
 axum = "0.7.0"
-axum-server = "0.6.0"
+axum-server = {version = "0.6.0", default-features = false}
 tower = "0.4.13"
 http = "1.0.0"
 tower-http = "0.5.1"
@@ -125,7 +126,7 @@ reqwest = "0.11.24"
 # It is not meant to be published, but is used so "cargo run --example XYZ" works properly
 [package]
 name = "dioxus-examples"
-version = "0.4.3"
+version = "0.5.0-alpha.0"
 authors = ["Jonathan Kelley"]
 edition = "2021"
 description = "Top level crate for the Dioxus repository"
@@ -192,4 +193,4 @@ required-features = ["http"]
 
 [[example]]
 name = "image_generator_openai"
-required-features = ["http"]
+required-features = ["http"]

+ 2 - 2
examples/PWA-example/Cargo.toml

@@ -8,8 +8,8 @@ publish = false
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-dioxus = { path = "../../packages/dioxus", version = "*" }
-dioxus-web = { path = "../../packages/web", version = "*" }
+dioxus = { workspace = true }
+dioxus-web = { workspace = true }
 
 log = "0.4.6"
 

+ 2 - 2
examples/future.rs

@@ -1,7 +1,7 @@
 //! A simple example that shows how to use the use_future hook to run a background task.
 //!
-//! use_future assumes your future will never complete - it won't return a value.
-//! If you want to return a value, use use_resource instead.
+//! use_future won't return a value, analagous to use_effect.
+//! If you want to return a value from a future, use use_resource instead.
 
 use dioxus::prelude::*;
 use std::time::Duration;

+ 1 - 0
examples/tailwind/.gitignore

@@ -0,0 +1 @@
+dist

+ 1 - 1
packages/cli-config/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = "dioxus-cli-config"
-version = "0.4.1"
+version = { workspace = true }
 authors = ["Jonathan Kelley"]
 edition = "2021"
 description = "Configuration for the Dioxus CLI"

+ 1 - 1
packages/cli/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = "dioxus-cli"
-version = "0.4.3"
+version = { workspace = true }
 authors = ["Jonathan Kelley"]
 edition = "2021"
 description = "CLI tool for developing, testing, and publishing Dioxus apps"

+ 2 - 0
packages/core/Cargo.toml

@@ -20,9 +20,11 @@ slab = { workspace = true }
 futures-channel = { workspace = true }
 tracing = { workspace = true }
 serde = { version = "1", features = ["derive"], optional = true }
+tracing-subscriber = "0.3.18"
 
 [dev-dependencies]
 tokio = { workspace = true, features = ["full"] }
+tracing-fluent-assertions = "0.3.0"
 dioxus = { workspace = true }
 pretty_assertions = "1.3.0"
 rand = "0.8.5"

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

@@ -21,6 +21,7 @@ use futures_util::StreamExt;
 use rustc_hash::{FxHashMap, FxHashSet};
 use slab::Slab;
 use std::{any::Any, collections::BTreeSet, rc::Rc};
+use tracing::instrument;
 
 /// A virtual node system that progresses user events and diffs UI trees.
 ///
@@ -305,6 +306,7 @@ impl VirtualDom {
     /// let mut dom = VirtualDom::new_from_root(VComponent::new(Example, SomeProps { name: "jane" }, "Example"));
     /// let mutations = dom.rebuild();
     /// ```
+    #[instrument(skip(root), level = "trace", name = "VirtualDom::new")]
     pub(crate) fn new_with_component(root: impl AnyProps + 'static) -> Self {
         let (tx, rx) = futures_channel::mpsc::unbounded();
 
@@ -347,6 +349,7 @@ impl VirtualDom {
     }
 
     /// Run a closure inside the dioxus runtime
+    #[instrument(skip(self, f), level = "trace", name = "VirtualDom::in_runtime")]
     pub fn in_runtime<O>(&self, f: impl FnOnce() -> O) -> O {
         let _runtime = RuntimeGuard::new(self.runtime.clone());
         f()
@@ -375,7 +378,7 @@ impl VirtualDom {
             return;
         };
 
-        tracing::trace!("Marking scope {:?} as dirty", id);
+        tracing::event!(tracing::Level::TRACE, "Marking scope {:?} as dirty", id);
         let order = ScopeOrder::new(scope.height(), id);
         self.dirty_scopes.queue_scope(order);
     }
@@ -388,6 +391,14 @@ impl VirtualDom {
         let Some(scope) = self.runtime.get_state(scope) else {
             return;
         };
+
+        tracing::event!(
+            tracing::Level::TRACE,
+            "Marking task {:?} (spawned in {:?}) as dirty",
+            task,
+            scope.id
+        );
+
         let order = ScopeOrder::new(scope.height(), scope.id);
         self.dirty_scopes.queue_task(task, order);
     }
@@ -401,6 +412,7 @@ impl VirtualDom {
     /// It is up to the listeners themselves to mark nodes as dirty.
     ///
     /// If you have multiple events, you can call this method multiple times before calling "render_with_deadline"
+    #[instrument(skip(self), level = "trace", name = "VirtualDom::handle_event")]
     pub fn handle_event(
         &mut self,
         name: &str,
@@ -434,12 +446,14 @@ impl VirtualDom {
     /// ```rust, ignore
     /// let dom = VirtualDom::new(app);
     /// ```
+    #[instrument(skip(self), level = "trace", name = "VirtualDom::wait_for_work")]
     pub async fn wait_for_work(&mut self) {
         // And then poll the futures
         self.poll_tasks().await;
     }
 
     /// Poll the scheduler for any work
+    #[instrument(skip(self), level = "trace", name = "VirtualDom::poll_tasks")]
     async fn poll_tasks(&mut self) {
         loop {
             // Process all events - Scopes are marked dirty, etc
@@ -478,6 +492,7 @@ impl VirtualDom {
     }
 
     /// Process all events in the queue until there are no more left
+    #[instrument(skip(self), level = "trace", name = "VirtualDom::process_events")]
     pub fn process_events(&mut self) {
         let _runtime = RuntimeGuard::new(self.runtime.clone());
         self.queue_events();
@@ -513,7 +528,8 @@ impl VirtualDom {
     ///
     /// The caller must ensure that the template references the same dynamic attributes and nodes as the original template.
     ///
-    /// This will only replace the the parent template, not any nested templates.
+    /// This will only replace the parent template, not any nested templates.
+    #[instrument(skip(self), level = "trace", name = "VirtualDom::replace_template")]
     pub fn replace_template(&mut self, template: Template) {
         self.register_template_first_byte_index(template);
         // iterating a slab is very inefficient, but this is a rare operation that will only happen during development so it's fine
@@ -552,7 +568,7 @@ impl VirtualDom {
     /// The mutations item expects the RealDom's stack to be the root of the application.
     ///
     /// Tasks will not be polled with this method, nor will any events be processed from the event queue. Instead, the
-    /// root component will be ran once and then diffed. All updates will flow out as mutations.
+    /// root component will be run once and then diffed. All updates will flow out as mutations.
     ///
     /// All state stored in components will be completely wiped away.
     ///
@@ -567,6 +583,7 @@ impl VirtualDom {
     ///
     /// apply_edits(edits);
     /// ```
+    #[instrument(skip(self, to), level = "trace", name = "VirtualDom::rebuild")]
     pub fn rebuild(&mut self, to: &mut impl WriteMutations) {
         self.flush_templates(to);
         let _runtime = RuntimeGuard::new(self.runtime.clone());
@@ -580,6 +597,7 @@ impl VirtualDom {
 
     /// Render whatever the VirtualDom has ready as fast as possible without requiring an executor to progress
     /// suspended subtrees.
+    #[instrument(skip(self, to), level = "trace", name = "VirtualDom::render_immediate")]
     pub fn render_immediate(&mut self, to: &mut impl WriteMutations) {
         self.flush_templates(to);
 
@@ -627,7 +645,8 @@ impl VirtualDom {
     /// The mutations will be thrown out, so it's best to use this method for things like SSR that have async content
     ///
     /// We don't call "flush_sync" here since there's no sync work to be done. Futures will be progressed like usual,
-    /// however any futures wating on flush_sync will remain pending
+    /// however any futures waiting on flush_sync will remain pending
+    #[instrument(skip(self), level = "trace", name = "VirtualDom::wait_for_suspense")]
     pub async fn wait_for_suspense(&mut self) {
         loop {
             if self.suspended_scopes.is_empty() {
@@ -648,6 +667,7 @@ impl VirtualDom {
     }
 
     /// Flush any queued template changes
+    #[instrument(skip(self, to), level = "trace", name = "VirtualDom::flush_templates")]
     fn flush_templates(&mut self, to: &mut impl WriteMutations) {
         for template in self.queued_templates.drain(..) {
             to.register_template(template);
@@ -675,6 +695,11 @@ impl VirtualDom {
     | | |       <-- no, broke early
     |           <-- no, broke early
     */
+    #[instrument(
+        skip(self, uievent),
+        level = "trace",
+        name = "VirtualDom::handle_bubbling_event"
+    )]
     fn handle_bubbling_event(
         &mut self,
         mut parent: Option<ElementRef>,
@@ -713,6 +738,11 @@ impl VirtualDom {
 
             // Now that we've accumulated all the parent attributes for the target element, call them in reverse order
             // We check the bubble state between each call to see if the event has been stopped from bubbling
+            tracing::event!(
+                tracing::Level::TRACE,
+                "Calling {} listeners",
+                listeners.len()
+            );
             for listener in listeners.into_iter().rev() {
                 if let AttributeValue::Listener(listener) = listener {
                     self.runtime.rendering.set(false);
@@ -731,6 +761,11 @@ impl VirtualDom {
     }
 
     /// Call an event listener in the simplest way possible without bubbling upwards
+    #[instrument(
+        skip(self, uievent),
+        level = "trace",
+        name = "VirtualDom::handle_non_bubbling_event"
+    )]
     fn handle_non_bubbling_event(&mut self, node: ElementRef, name: &str, uievent: Event<dyn Any>) {
         let el_ref = &self.mounts[node.mount.0].node;
         let node_template = el_ref.template.get();

+ 5 - 9
packages/core/tests/fuzzing.rs

@@ -2,7 +2,9 @@
 
 use dioxus::prelude::*;
 use dioxus_core::{AttributeValue, DynamicNode, NoOpMutations, VComponent, VNode, *};
-use std::{cfg, collections::HashSet, default::Default};
+use std::{
+    cfg, collections::HashSet, default::Default, sync::atomic::AtomicUsize, sync::atomic::Ordering,
+};
 
 fn random_ns() -> Option<&'static str> {
     let namespace = rand::random::<u8>() % 2;
@@ -220,20 +222,14 @@ fn create_random_dynamic_attr() -> Attribute {
     )
 }
 
-static mut TEMPLATE_COUNT: usize = 0;
+static TEMPLATE_COUNT: AtomicUsize = AtomicUsize::new(0);
 
 fn create_template_location() -> &'static str {
     Box::leak(
         format!(
             "{}{}",
             concat!(file!(), ":", line!(), ":", column!(), ":"),
-            {
-                unsafe {
-                    let old = TEMPLATE_COUNT;
-                    TEMPLATE_COUNT += 1;
-                    old
-                }
-            }
+            TEMPLATE_COUNT.fetch_add(1, Ordering::Relaxed)
         )
         .into_boxed_str(),
     )

+ 82 - 0
packages/core/tests/tracing.rs

@@ -0,0 +1,82 @@
+use dioxus::html::SerializedHtmlEventConverter;
+use dioxus::prelude::*;
+use dioxus_core::ElementId;
+use std::rc::Rc;
+use tracing_fluent_assertions::{AssertionRegistry, AssertionsLayer};
+use tracing_subscriber::{layer::SubscriberExt, Registry};
+
+#[test]
+fn basic_tracing() {
+    // setup tracing
+    let assertion_registry = AssertionRegistry::default();
+    let base_subscriber = Registry::default();
+    // log to standard out for testing
+    let std_out_log = tracing_subscriber::fmt::layer().pretty();
+    let subscriber = base_subscriber
+        .with(std_out_log)
+        .with(AssertionsLayer::new(&assertion_registry));
+    tracing::subscriber::set_global_default(subscriber).unwrap();
+
+    let new_virtual_dom = assertion_registry
+        .build()
+        .with_name("VirtualDom::new")
+        .was_created()
+        .was_entered_exactly(1)
+        .was_closed()
+        .finalize();
+
+    let edited_virtual_dom = assertion_registry
+        .build()
+        .with_name("VirtualDom::rebuild")
+        .was_created()
+        .was_entered_exactly(1)
+        .was_closed()
+        .finalize();
+
+    set_event_converter(Box::new(SerializedHtmlEventConverter));
+    let mut dom = VirtualDom::new(app);
+
+    dom.rebuild(&mut dioxus_core::NoOpMutations);
+
+    new_virtual_dom.assert();
+    edited_virtual_dom.assert();
+
+    for _ in 0..3 {
+        dom.handle_event(
+            "click",
+            Rc::new(PlatformEventData::new(Box::<SerializedMouseData>::default())),
+            ElementId(2),
+            true,
+        );
+        dom.process_events();
+        _ = dom.render_immediate_to_vec();
+    }
+}
+
+fn app() -> Element {
+    let mut idx = use_signal(|| 0);
+    let onhover = |_| println!("go!");
+
+    rsx! {
+        div {
+            button {
+                onclick: move |_| {
+                    idx += 1;
+                    println!("Clicked");
+                },
+                "+"
+            }
+            button { onclick: move |_| idx -= 1, "-" }
+            ul {
+                {(0..idx()).map(|i| rsx! {
+                    ChildExample { i: i, onhover: onhover }
+                })}
+            }
+        }
+    }
+}
+
+#[component]
+fn ChildExample(i: i32, onhover: EventHandler<MouseEvent>) -> Element {
+    rsx! { li { onmouseover: move |e| onhover.call(e), "{i}" } }
+}

+ 3 - 2
packages/desktop/headless_tests/events.rs

@@ -14,8 +14,9 @@ pub(crate) fn check_app_exits(app: fn() -> Element) {
     let should_panic = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(true));
     let should_panic_clone = should_panic.clone();
     std::thread::spawn(move || {
-        std::thread::sleep(std::time::Duration::from_secs(30));
+        std::thread::sleep(std::time::Duration::from_secs(60));
         if should_panic_clone.load(std::sync::atomic::Ordering::SeqCst) {
+            eprintln!("App did not exit in time");
             std::process::exit(exitcode::SOFTWARE);
         }
     });
@@ -31,7 +32,7 @@ pub(crate) fn check_app_exits(app: fn() -> Element) {
 fn mock_event(id: &'static str, value: &'static str) {
     use_hook(move || {
         spawn(async move {
-            tokio::time::sleep(std::time::Duration::from_millis(2000)).await;
+            tokio::time::sleep(std::time::Duration::from_millis(5000)).await;
 
             let js = format!(
                 r#"

+ 4 - 3
packages/desktop/src/protocol.rs

@@ -43,6 +43,7 @@ fn handle_edits_code() -> String {
     }"#;
     let polling_request = format!(
         r#"// Poll for requests
+    window.interpreter = new JSChannel();
     window.interpreter.wait_for_request = (headless) => {{
       fetch(new Request("{EDITS_PATH}"))
           .then(response => {{
@@ -50,11 +51,11 @@ fn handle_edits_code() -> String {
                   .then(bytes => {{
                       // In headless mode, the requestAnimationFrame callback is never called, so we need to run the bytes directly
                       if (headless) {{
-                        run_from_bytes(bytes);
+                        window.interpreter.run_from_bytes(bytes);
                       }}
                       else {{
                         requestAnimationFrame(() => {{
-                          run_from_bytes(bytes);
+                            window.interpreter.run_from_bytes(bytes);
                         }});
                       }}
                       window.interpreter.wait_for_request(headless);
@@ -74,7 +75,7 @@ fn handle_edits_code() -> String {
         interpreter.replace_range(import_start..import_end, "");
     }
 
-    format!("{interpreter}\nconst config = new InterpreterConfig(true);")
+    format!("{interpreter}\nconst intercept_link_redirects = true;")
 }
 
 static DEFAULT_INDEX: &str = include_str!("./index.html");

+ 1 - 2
packages/extension/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = "dioxus-ext"
-version = "0.1.0"
+version = { workspace = true }
 edition = "2021"
 publish = false
 
@@ -12,6 +12,5 @@ dioxus-autofmt = { workspace = true }
 rsx-rosetta = { workspace = true }
 html_parser = { workspace = true }
 
-
 [lib]
 crate-type = ["cdylib", "rlib"]

+ 2 - 2
packages/extension/package.json

@@ -2,14 +2,14 @@
     "name": "dioxus",
     "displayName": "Dioxus",
     "description": "Useful tools for working with Dioxus",
-    "version": "0.0.2",
+    "version": "0.4.0",
     "publisher": "DioxusLabs",
     "private": true,
     "license": "MIT",
     "icon": "static/icon.png",
     "repository": {
         "type": "git",
-        "url": "https://github.com/DioxusLabs/cli"
+        "url": "https://github.com/DioxusLabs/dioxus"
     },
     "engines": {
         "vscode": "^1.68.1"

+ 3 - 3
packages/fullstack/Cargo.toml

@@ -13,10 +13,10 @@ resolver = "2"
 [dependencies]
 # server functions
 server_fn = { version = "0.6.5", features = ["json", "url", "browser"], default-features = false }
-dioxus_server_macro = { workspace = true, version = "0.6.5", default-features = false }
+dioxus_server_macro = { workspace = true }
 
 # axum
-axum = { workspace = true, features = ["ws", "macros"], default-features = false, optional = true }
+axum = { workspace = true, features = ["ws", "macros"], optional = true }
 tower-http = { workspace = true, optional = true, features = ["fs", "compression-gzip"] }
 
 dioxus-lib = { workspace = true }
@@ -44,7 +44,7 @@ anymap = { version = "0.12.1", optional = true }
 serde = "1.0.159"
 serde_json = { version = "1.0.95", optional = true }
 tokio-stream = { version = "0.1.12", features = ["sync"], optional = true }
-futures-util = { workspace = true, default-features = false }
+futures-util = { workspace = true }
 ciborium = "0.2.1"
 base64 = "0.21.0"
 

+ 1 - 1
packages/generational-box/Cargo.toml

@@ -1,7 +1,7 @@
 [package]
 name = "generational-box"
 authors = ["Evan Almloff"]
-version = "0.4.3"
+version = { workspace = true }
 edition = "2021"
 description = "A box backed by a generational runtime"
 license = "MIT OR Apache-2.0"

+ 30 - 0
packages/hooks/src/use_context.rs

@@ -14,6 +14,18 @@ pub fn try_use_context<T: 'static + Clone>() -> Option<T> {
 /// Consume some context in the tree, providing a sharable handle to the value
 ///
 /// Does not regenerate the value if the value is changed at the parent.
+/// ```rust
+/// fn Parent() -> Element {
+///     use_context_provider(|| Theme::Dark);
+///     rsx! { Child {} }
+/// }
+/// #[component]
+/// fn Child() -> Element {
+///     //gets context provided by parent element with use_context_provider
+///     let user_theme = use_context::<Theme>();
+///     rsx! { "user using dark mode: {user_theme == Theme::Dark}" }
+/// }
+/// ```
 #[must_use]
 pub fn use_context<T: 'static + Clone>() -> T {
     use_hook(|| consume_context::<T>())
@@ -22,6 +34,24 @@ pub fn use_context<T: 'static + Clone>() -> T {
 /// Provide some context via the tree and return a reference to it
 ///
 /// Once the context has been provided, it is immutable. Mutations should be done via interior mutability.
+/// Context can be read by any child components of the context provider, and is a solution to prop
+/// drilling, using a context provider with a Signal inside is a good way to provide global/shared
+/// state in your app:
+/// ```rust
+///fn app() -> Element {
+///    use_context_provider(|| Signal::new(0));
+///    rsx! { Child {} }
+///}
+/// // This component does read from the signal, so when the signal changes it will rerun
+///#[component]
+///fn Child() -> Element {
+///     let signal: Signal<i32> = use_context();
+///     rsx! {
+///         button { onclick: move |_| signal += 1, "increment context" }
+///         p {"{signal}"}
+///     }
+///}
+/// ```
 pub fn use_context_provider<T: 'static + Clone>(f: impl FnOnce() -> T) -> T {
     use_hook(|| {
         let val = f();

+ 2 - 1
packages/hooks/src/use_coroutine.rs

@@ -93,7 +93,8 @@ where
 }
 
 /// Get a handle to a coroutine higher in the tree
-///
+/// Analagous to use_context_provider and use_context,
+/// but used for coroutines specifically
 /// See the docs for [`use_coroutine`] for more details.
 #[must_use]
 pub fn use_coroutine_handle<M: 'static>() -> Coroutine<M> {

+ 15 - 3
packages/hooks/src/use_effect.rs

@@ -1,10 +1,22 @@
 use dioxus_core::prelude::*;
 use dioxus_signals::ReactiveContext;
 
-/// Create a new effect. The effect will be run immediately and whenever any signal it reads changes.
-/// The signal will be owned by the current component and will be dropped when the component is dropped.
-///
+/// `use_effect` will subscribe to any changes in the signal values it captures
+/// effects will always run after first mount and then whenever the signal values change
 /// If the use_effect call was skipped due to an early return, the effect will no longer activate.
+/// ```rust
+/// fn app() -> Element {
+///     let mut count = use_signal(|| 0);
+///     //the effect runs again each time count changes
+///     use_effect(move || println!("Count changed to {count}"));
+///
+///     rsx! {
+///         h1 { "High-Five counter: {count}" }
+///         button { onclick: move |_| count += 1, "Up high!" }
+///         button { onclick: move |_| count -= 1, "Down low!" }
+///     }
+/// }
+/// ```
 #[track_caller]
 pub fn use_effect(mut callback: impl FnMut() + 'static) {
     // let mut run_effect = use_hook(|| CopyValue::new(true));

+ 26 - 2
packages/hooks/src/use_future.rs

@@ -8,10 +8,34 @@ use dioxus_signals::*;
 use dioxus_signals::{Readable, Writable};
 use std::future::Future;
 
-/// A hook that allows you to spawn a future
-///
+/// A hook that allows you to spawn a future.
+/// This future will **not** run on the server
 /// The future is spawned on the next call to `flush_sync` which means that it will not run on the server.
 /// To run a future on the server, you should use `spawn` directly.
+/// `use_future` **won't return a value**.
+/// If you want to return a value from a future, use `use_resource` instead.
+/// ```rust
+/// fn app() -> Element {
+///     let mut count = use_signal(|| 0);
+///     let mut running = use_signal(|| true);
+///     // `use_future` will spawn an infinitely running future that can be started and stopped
+///     use_future(move || async move {
+///         loop {
+///            if running() {
+///                count += 1;
+///            }
+///            tokio::time::sleep(Duration::from_millis(400)).await;
+///        }
+///     });
+///     rsx! {
+///         div {
+///             h1 { "Current count: {count}" }
+///             button { onclick: move |_| running.toggle(), "Start/Stop the count"}
+///             button { onclick: move |_| count.set(0), "Reset the count" }
+///         }
+///     }
+/// }
+/// ```
 pub fn use_future<F>(mut future: impl FnMut() -> F + 'static) -> UseFuture
 where
     F: Future + 'static,

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

@@ -10,8 +10,32 @@ use futures_util::{future, pin_mut, FutureExt};
 use std::future::Future;
 
 /// A memo that resolve to a value asynchronously.
+/// Unlike `use_future`, `use_resource` runs on the **server**
+/// See [`Resource`] for more details.
+/// ```rust
+///fn app() -> Element {
+///    let country = use_signal(|| WeatherLocation {
+///        city: "Berlin".to_string(),
+///        country: "Germany".to_string(),
+///        coordinates: (52.5244, 13.4105)
+///    });
 ///
-/// This runs on the server
+///    let current_weather = //run a future inside the use_resource hook
+///        use_resource(move || async move { get_weather(&country.read().clone()).await });
+///    
+///    rsx! {
+///        //the value of the future can be polled to
+///        //conditionally render elements based off if the future
+///        //finished (Some(Ok(_)), errored Some(Err(_)),
+///        //or is still finishing (None)
+///        match current_weather.value() {
+///            Some(Ok(weather)) => WeatherElement { weather },
+///            Some(Err(e)) => p { "Loading weather failed, {e}" }
+///            None =>  p { "Loading..." }
+///        }
+///    }
+///}
+/// ```
 #[must_use = "Consider using `cx.spawn` to run a future without reading its value"]
 pub fn use_resource<T, F>(future: impl Fn() -> F + 'static) -> Resource<T>
 where

+ 1 - 1
packages/html-internal-macro/Cargo.toml

@@ -25,4 +25,4 @@ name = "tests"
 path = "tests/progress.rs"
 
 [dev-dependencies]
-trybuild = { version = "1.0.82", features = ["diff"] }
+trybuild = { version = "1.0.82", features = ["diff"] }

+ 4 - 4
packages/html/src/elements.rs

@@ -1613,10 +1613,10 @@ builder_constructors! {
     /// element.
     hatchpath "http://www.w3.org/2000/svg" {};
 
-    // /// Build a
-    // /// [`<image>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/image)
-    // /// element.
-    // image "http://www.w3.org/2000/svg" {};
+    /// Build a
+    /// [`<image>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/image)
+    /// element.
+    image "http://www.w3.org/2000/svg" {};
 
     /// Build a
     /// [`<line>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/line)

+ 2 - 2
packages/html/src/global_attributes.rs

@@ -2285,8 +2285,8 @@ trait_methods! {
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/transform-origin>
     transform_origin: "transform-origin";
 
-    /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/_type>
-    r#type: "_type";
+    /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/type>
+    r#type: "type";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/u1>
     u1: "u1";

+ 1 - 1
packages/interpreter/Cargo.toml

@@ -17,7 +17,7 @@ web-sys = { version = "0.3.56", optional = true, features = [
     "Element",
     "Node",
 ] }
-sledgehammer_bindgen = { version = "0.3.1", default-features = false, optional = true }
+sledgehammer_bindgen = { version = "0.4.0", default-features = false, optional = true }
 sledgehammer_utils = { version = "0.2", optional = true }
 serde = { version = "1.0", features = ["derive"], optional = true }
 

+ 1 - 1
packages/interpreter/src/common.js

@@ -1,4 +1,4 @@
-export function setAttributeInner(node, field, value, ns) {
+this.setAttributeInner = function (node, field, value, ns) {
   const name = field;
   if (ns === "style") {
     // ????? why do we need to do this

+ 79 - 0
packages/interpreter/src/common_exported.js

@@ -0,0 +1,79 @@
+export function setAttributeInner(node, field, value, ns) {
+  const name = field;
+  if (ns === "style") {
+    // ????? why do we need to do this
+    if (node.style === undefined) {
+      node.style = {};
+    }
+    node.style[name] = value;
+  } else if (!!ns) {
+    node.setAttributeNS(ns, name, value);
+  } else {
+    switch (name) {
+      case "value":
+        if (value !== node.value) {
+          node.value = value;
+        }
+        break;
+      case "initial_value":
+        node.defaultValue = value;
+        break;
+      case "checked":
+        node.checked = truthy(value);
+        break;
+      case "initial_checked":
+        node.defaultChecked = truthy(value);
+        break;
+      case "selected":
+        node.selected = truthy(value);
+        break;
+      case "initial_selected":
+        node.defaultSelected = truthy(value);
+        break;
+      case "dangerous_inner_html":
+        node.innerHTML = value;
+        break;
+      default:
+        // https://github.com/facebook/react/blob/8b88ac2592c5f555f315f9440cbb665dd1e7457a/packages/react-dom/src/shared/DOMProperty.js#L352-L364
+        if (!truthy(value) && bool_attrs.hasOwnProperty(name)) {
+          node.removeAttribute(name);
+        } else {
+          node.setAttribute(name, value);
+        }
+    }
+  }
+}
+
+const bool_attrs = {
+  allowfullscreen: true,
+  allowpaymentrequest: true,
+  async: true,
+  autofocus: true,
+  autoplay: true,
+  checked: true,
+  controls: true,
+  default: true,
+  defer: true,
+  disabled: true,
+  formnovalidate: true,
+  hidden: true,
+  ismap: true,
+  itemscope: true,
+  loop: true,
+  multiple: true,
+  muted: true,
+  nomodule: true,
+  novalidate: true,
+  open: true,
+  playsinline: true,
+  readonly: true,
+  required: true,
+  reversed: true,
+  selected: true,
+  truespeed: true,
+  webkitdirectory: true,
+};
+
+function truthy(val) {
+  return val === "true" || val === true;
+}

+ 29 - 38
packages/interpreter/src/interpreter.js

@@ -1,12 +1,6 @@
-class InterpreterConfig {
-  constructor(intercept_link_redirects) {
-    this.intercept_link_redirects = intercept_link_redirects;
-  }
-}
-
 // this handler is only provided on the desktop and liveview implementations since this
 // method is not used by the web implementation
-async function handler(event, name, bubbles, config) {
+this.handler = async function (event, name, bubbles) {
   let target = event.target;
   if (target != null) {
     let preventDefaultRequests = null;
@@ -17,7 +11,7 @@ async function handler(event, name, bubbles, config) {
 
     if (event.type === "click") {
       // todo call prevent default if it's the right type of event
-      if (config.intercept_link_redirects) {
+      if (intercept_link_redirects) {
         let a_element = target.closest("a");
         if (a_element != null) {
           event.preventDefault();
@@ -35,7 +29,7 @@ async function handler(event, name, bubbles, config) {
             const href = a_element.getAttribute("href");
             if (href !== "" && href !== null && href !== undefined) {
               window.ipc.postMessage(
-                window.interpreter.serializeIpcMessage("browser_open", { href })
+                this.serializeIpcMessage("browser_open", { href })
               );
             }
           }
@@ -142,7 +136,7 @@ async function handler(event, name, bubbles, config) {
       return;
     }
     window.ipc.postMessage(
-      window.interpreter.serializeIpcMessage("user_event", {
+      this.serializeIpcMessage("user_event", {
         name: name,
         element: parseInt(realId),
         data: contents,
@@ -223,43 +217,40 @@ class ListenerMap {
     delete this.local[id];
   }
 }
-function LoadChild(array) {
+this.LoadChild = function (array) {
   // iterate through each number and get that child
-  node = stack[stack.length - 1];
+  let node = this.stack[this.stack.length - 1];
 
   for (let i = 0; i < array.length; i++) {
-    end = array[i];
-    for (node = node.firstChild; end > 0; end--) {
+    this.end = array[i];
+    for (node = node.firstChild; this.end > 0; this.end--) {
       node = node.nextSibling;
     }
   }
   return node;
 }
-const listeners = new ListenerMap();
-let nodes = [];
-let stack = [];
-let root;
-const templates = {};
-let node, els, end, k;
-
-function AppendChildren(id, many) {
-  root = nodes[id];
-  els = stack.splice(stack.length - many);
-  for (k = 0; k < many; k++) {
+this.listeners = new ListenerMap();
+this.nodes = [];
+this.stack = [];
+this.templates = {};
+this.end = null;
+
+this.AppendChildren = function (id, many) {
+  let root = this.nodes[id];
+  let els = this.stack.splice(this.stack.length - many);
+  for (let k = 0; k < many; k++) {
     root.appendChild(els[k]);
   }
 }
 
-window.interpreter = {}
-
-window.interpreter.initialize = function (root) {
-  nodes = [root];
-  stack = [root];
-  listeners.root = root;
+this.initialize = function (root) {
+  this.nodes = [root];
+  this.stack = [root];
+  this.listeners.root = root;
 }
 
-window.interpreter.getClientRect = function (id) {
-  const node = nodes[id];
+this.getClientRect = function (id) {
+  const node = this.nodes[id];
   if (!node) {
     return;
   }
@@ -271,8 +262,8 @@ window.interpreter.getClientRect = function (id) {
   };
 }
 
-window.interpreter.scrollTo = function (id, behavior) {
-  const node = nodes[id];
+this.scrollTo = function (id, behavior) {
+  const node = this.nodes[id];
   if (!node) {
     return false;
   }
@@ -283,8 +274,8 @@ window.interpreter.scrollTo = function (id, behavior) {
 }
 
 /// Set the focus on the element
-window.interpreter.setFocus = function (id, focus) {
-  const node = nodes[id];
+this.setFocus = function (id, focus) {
+  const node = this.nodes[id];
   if (!node) {
     return false;
   }
@@ -579,7 +570,7 @@ async function serialize_event(event) {
     }
   }
 }
-window.interpreter.serializeIpcMessage = function (method, params = {}) {
+this.serializeIpcMessage = function (method, params = {}) {
   return JSON.stringify({ method, params });
 }
 

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

@@ -20,7 +20,7 @@ pub use write_native_mutations::*;
 #[cfg(all(feature = "minimal_bindings", feature = "webonly"))]
 pub mod minimal_bindings {
     use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
-    #[wasm_bindgen(module = "/src/common.js")]
+    #[wasm_bindgen(module = "/src/common_exported.js")]
     extern "C" {
         pub fn setAttributeInner(node: JsValue, name: &str, value: JsValue, ns: Option<&str>);
     }

+ 105 - 99
packages/interpreter/src/sledgehammer_bindings.rs

@@ -19,7 +19,7 @@ mod js {
             this.global = {};
             // non bubbling events listen at the element the listener was created at
             this.local = {};
-            this.root = null;
+            this.root = root;
             this.handler = null;
         }
 
@@ -65,35 +65,33 @@ mod js {
             delete this.local[id];
         }
     }
-    function LoadChild(ptr, len) {
+    this.LoadChild = function(ptr, len) {
         // iterate through each number and get that child
-        node = stack[stack.length - 1];
-        ptr_end = ptr + len;
+        let node = this.stack[this.stack.length - 1];
+        let ptr_end = ptr + len;
         for (; ptr < ptr_end; ptr++) {
-            end = m.getUint8(ptr);
+            let end = this.m.getUint8(ptr);
             for (node = node.firstChild; end > 0; end--) {
                 node = node.nextSibling;
             }
         }
         return node;
     }
-    const listeners = new ListenerMap();
-    let nodes = [];
-    let stack = [];
-    let root;
-    const templates = {};
-    let node, els, end, ptr_end, k;
-    export function save_template(nodes, tmpl_id) {
-        templates[tmpl_id] = nodes;
+    this.listeners = new ListenerMap();
+    this.nodes = [];
+    this.stack = [];
+    this.templates = {};
+    this.save_template = function(nodes, tmpl_id) {
+        this.templates[tmpl_id] = nodes;
     }
-    export function hydrate(ids) {
+    this.hydrate = function (ids) {
         const hydrateNodes = document.querySelectorAll('[data-node-hydration]');
         for (let i = 0; i < hydrateNodes.length; i++) {
             const hydrateNode = hydrateNodes[i];
             const hydration = hydrateNode.getAttribute('data-node-hydration');
             const split = hydration.split(',');
             const id = ids[parseInt(split[0])];
-            nodes[id] = hydrateNode;
+            this.nodes[id] = hydrateNode;
             if (split.length > 1) {
                 hydrateNode.listening = split.length - 1;
                 hydrateNode.setAttribute('data-dioxus-id', id);
@@ -102,7 +100,7 @@ mod js {
                     const split2 = listener.split(':');
                     const event_name = split2[0];
                     const bubbles = split2[1] === '1';
-                    listeners.create(event_name, hydrateNode, bubbles);
+                    this.listeners.create(event_name, hydrateNode, bubbles);
                 }
             }
         }
@@ -115,91 +113,77 @@ mod js {
             const id = currentNode.textContent;
             const split = id.split('node-id');
             if (split.length > 1) {
-                nodes[ids[parseInt(split[1])]] = currentNode.nextSibling;
+                this.nodes[ids[parseInt(split[1])]] = currentNode.nextSibling;
             }
             currentNode = treeWalker.nextNode();
         }
     }
-    export function get_node(id) {
-        return nodes[id];
+    this.get_node = function(id) {
+        return this.nodes[id];
     }
-    export function initialize(root, handler) {
-        listeners.handler = handler;
-        nodes = [root];
-        stack = [root];
-        listeners.root = root;
+    this.initialize = function(root, handler) {
+        this.listeners.handler = handler;
+        this.nodes = [root];
+        this.stack = [root];
+        this.listeners.root = root;
     }
-    function AppendChildren(id, many){
-        root = nodes[id];
-        els = stack.splice(stack.length-many);
-        for (k = 0; k < many; k++) {
+    this.AppendChildren = function (id, many){
+        let root = this.nodes[id];
+        let els = this.stack.splice(this.stack.length-many);
+        for (let k = 0; k < many; k++) {
             root.appendChild(els[k]);
         }
     }
     "#;
 
-    extern "C" {
-        #[wasm_bindgen]
-        pub fn save_template(nodes: Vec<Node>, tmpl_id: u16);
-
-        #[wasm_bindgen]
-        pub fn hydrate(ids: Vec<u32>);
-
-        #[wasm_bindgen]
-        pub fn get_node(id: u32) -> Node;
-
-        #[wasm_bindgen]
-        pub fn initialize(root: Node, handler: &Function);
-    }
-
     fn mount_to_root() {
-        "{AppendChildren(root, stack.length-1);}"
+        "{this.AppendChildren(this.listeners.root, this.stack.length-1);}"
     }
     fn push_root(root: u32) {
-        "{stack.push(nodes[$root$]);}"
+        "{this.stack.push(this.nodes[$root$]);}"
     }
     fn append_children(id: u32, many: u16) {
-        "{AppendChildren($id$, $many$);}"
+        "{this.AppendChildren($id$, $many$);}"
     }
     fn pop_root() {
-        "{stack.pop();}"
+        "{this.stack.pop();}"
     }
     fn replace_with(id: u32, n: u16) {
-        "{root = nodes[$id$]; els = stack.splice(stack.length-$n$); if (root.listening) { listeners.removeAllNonBubbling(root); } root.replaceWith(...els);}"
+        "{const root = this.nodes[$id$]; let els = this.stack.splice(this.stack.length-$n$); if (root.listening) { this.listeners.removeAllNonBubbling(root); } root.replaceWith(...els);}"
     }
     fn insert_after(id: u32, n: u16) {
-        "{nodes[$id$].after(...stack.splice(stack.length-$n$));}"
+        "{this.nodes[$id$].after(...this.stack.splice(this.stack.length-$n$));}"
     }
     fn insert_before(id: u32, n: u16) {
-        "{nodes[$id$].before(...stack.splice(stack.length-$n$));}"
+        "{this.nodes[$id$].before(...this.stack.splice(this.stack.length-$n$));}"
     }
     fn remove(id: u32) {
-        "{node = nodes[$id$]; if (node !== undefined) { if (node.listening) { listeners.removeAllNonBubbling(node); } node.remove(); }}"
+        "{let node = this.nodes[$id$]; if (node !== undefined) { if (node.listening) { this.listeners.removeAllNonBubbling(node); } node.remove(); }}"
     }
     fn create_raw_text(text: &str) {
-        "{stack.push(document.createTextNode($text$));}"
+        "{this.stack.push(document.createTextNode($text$));}"
     }
     fn create_text_node(text: &str, id: u32) {
-        "{node = document.createTextNode($text$); nodes[$id$] = node; stack.push(node);}"
+        "{let node = document.createTextNode($text$); this.nodes[$id$] = node; this.stack.push(node);}"
     }
     fn create_placeholder(id: u32) {
-        "{node = document.createElement('pre'); node.hidden = true; stack.push(node); nodes[$id$] = node;}"
+        "{let node = document.createElement('pre'); node.hidden = true; this.stack.push(node); this.nodes[$id$] = node;}"
     }
     fn new_event_listener(event_name: &str<u8, evt>, id: u32, bubbles: u8) {
-        r#"node = nodes[id]; if(node.listening){node.listening += 1;}else{node.listening = 1;} node.setAttribute('data-dioxus-id', `\${id}`); listeners.create($event_name$, node, $bubbles$);"#
+        r#"let node = this.nodes[id]; if(node.listening){node.listening += 1;}else{node.listening = 1;} node.setAttribute('data-dioxus-id', `\${id}`); this.listeners.create($event_name$, node, $bubbles$);"#
     }
     fn remove_event_listener(event_name: &str<u8, evt>, id: u32, bubbles: u8) {
-        "{node = nodes[$id$]; node.listening -= 1; node.removeAttribute('data-dioxus-id'); listeners.remove(node, $event_name$, $bubbles$);}"
+        "{let node = this.nodes[$id$]; node.listening -= 1; node.removeAttribute('data-dioxus-id'); this.listeners.remove(node, $event_name$, $bubbles$);}"
     }
     fn set_text(id: u32, text: &str) {
-        "{nodes[$id$].textContent = $text$;}"
+        "{this.nodes[$id$].textContent = $text$;}"
     }
     fn set_attribute(id: u32, field: &str<u8, attr>, value: &str, ns: &str<u8, ns_cache>) {
-        "{node = nodes[$id$]; setAttributeInner(node, $field$, $value$, $ns$);}"
+        "{let node = this.nodes[$id$]; this.setAttributeInner(node, $field$, $value$, $ns$);}"
     }
     fn remove_attribute(id: u32, field: &str<u8, attr>, ns: &str<u8, ns_cache>) {
         r#"{
-            node = nodes[$id$];
+            let node = this.nodes[$id$];
             if (!ns) {
                 switch (field) {
                     case "value":
@@ -226,29 +210,54 @@ mod js {
         }"#
     }
     fn assign_id(ptr: u32, len: u8, id: u32) {
-        "{nodes[$id$] = LoadChild($ptr$, $len$);}"
+        "{this.nodes[$id$] = this.LoadChild($ptr$, $len$);}"
     }
     fn hydrate_text(ptr: u32, len: u8, value: &str, id: u32) {
         r#"{
-            node = LoadChild($ptr$, $len$);
-            if (node.nodeType == Node.TEXT_NODE) {
+            let node = this.LoadChild($ptr$, $len$);
+            if (node.nodeType == node.TEXT_NODE) {
                 node.textContent = value;
             } else {
                 let text = document.createTextNode(value);
                 node.replaceWith(text);
                 node = text;
             }
-            nodes[$id$] = node;
+            this.nodes[$id$] = node;
         }"#
     }
     fn replace_placeholder(ptr: u32, len: u8, n: u16) {
-        "{els = stack.splice(stack.length - $n$); node = LoadChild($ptr$, $len$); node.replaceWith(...els);}"
+        "{els = this.stack.splice(this.stack.length - $n$); let node = this.LoadChild($ptr$, $len$); node.replaceWith(...els);}"
     }
     fn load_template(tmpl_id: u16, index: u16, id: u32) {
-        "{node = templates[$tmpl_id$][$index$].cloneNode(true); nodes[$id$] = node; stack.push(node);}"
+        "{let node = this.templates[$tmpl_id$][$index$].cloneNode(true); this.nodes[$id$] = node; this.stack.push(node);}"
     }
 }
 
+#[cfg(feature = "webonly")]
+#[wasm_bindgen::prelude::wasm_bindgen(inline_js = r#"
+export function save_template(channel, nodes, tmpl_id) {
+    channel.save_template(nodes, tmpl_id);
+}
+export function hydrate(channel, ids) {
+    channel.hydrate(ids);
+}
+export function get_node(channel, id) {
+    return channel.get_node(id);
+}
+export function initialize(channel, root, handler) {
+    channel.initialize(root, handler);
+}
+"#)]
+extern "C" {
+    pub fn save_template(channel: &JSChannel, nodes: Vec<Node>, tmpl_id: u16);
+
+    pub fn hydrate(channel: &JSChannel, ids: Vec<u32>);
+
+    pub fn get_node(channel: &JSChannel, id: u32) -> Node;
+
+    pub fn initialize(channel: &JSChannel, root: Node, handler: &Function);
+}
+
 #[cfg(feature = "binary-protocol")]
 pub mod binary_protocol {
     use sledgehammer_bindgen::bindgen;
@@ -259,61 +268,58 @@ pub mod binary_protocol {
         const JS_FILE: &str = "./src/interpreter.js";
         const JS_FILE: &str = "./src/common.js";
 
-        fn mount_to_root() {
-            "{AppendChildren(root, stack.length-1);}"
-        }
         fn push_root(root: u32) {
-            "{stack.push(nodes[$root$]);}"
+            "{this.stack.push(this.nodes[$root$]);}"
         }
         fn append_children(id: u32, many: u16) {
-            "{AppendChildren($id$, $many$);}"
+            "{this.AppendChildren($id$, $many$);}"
         }
         fn append_children_to_top(many: u16) {
             "{
-                root = stack[stack.length-many-1];
-                els = stack.splice(stack.length-many);
-                for (k = 0; k < many; k++) {
+                let root = this.stack[this.stack.length-many-1];
+                let els = this.stack.splice(this.stack.length-many);
+                for (let k = 0; k < many; k++) {
                     root.appendChild(els[k]);
                 }
             }"
         }
         fn pop_root() {
-            "{stack.pop();}"
+            "{this.stack.pop();}"
         }
         fn replace_with(id: u32, n: u16) {
-            "{root = nodes[$id$]; els = stack.splice(stack.length-$n$); if (root.listening) { listeners.removeAllNonBubbling(root); } root.replaceWith(...els);}"
+            "{let root = this.nodes[$id$]; let els = this.stack.splice(this.stack.length-$n$); if (root.listening) { this.listeners.removeAllNonBubbling(root); } root.replaceWith(...els);}"
         }
         fn insert_after(id: u32, n: u16) {
-            "{nodes[$id$].after(...stack.splice(stack.length-$n$));}"
+            "{this.nodes[$id$].after(...this.stack.splice(this.stack.length-$n$));}"
         }
         fn insert_before(id: u32, n: u16) {
-            "{nodes[$id$].before(...stack.splice(stack.length-$n$));}"
+            "{this.nodes[$id$].before(...this.stack.splice(this.stack.length-$n$));}"
         }
         fn remove(id: u32) {
-            "{node = nodes[$id$]; if (node !== undefined) { if (node.listening) { listeners.removeAllNonBubbling(node); } node.remove(); }}"
+            "{let node = this.nodes[$id$]; if (node !== undefined) { if (node.listening) { this.listeners.removeAllNonBubbling(node); } node.remove(); }}"
         }
         fn create_raw_text(text: &str) {
-            "{stack.push(document.createTextNode($text$));}"
+            "{this.stack.push(document.createTextNode($text$));}"
         }
         fn create_text_node(text: &str, id: u32) {
-            "{node = document.createTextNode($text$); nodes[$id$] = node; stack.push(node);}"
+            "{let node = document.createTextNode($text$); this.nodes[$id$] = node; this.stack.push(node);}"
         }
         fn create_element(element: &'static str<u8, el>) {
-            "{stack.push(document.createElement($element$))}"
+            "{this.stack.push(document.createElement($element$))}"
         }
         fn create_element_ns(element: &'static str<u8, el>, ns: &'static str<u8, namespace>) {
-            "{stack.push(document.createElementNS($ns$, $element$))}"
+            "{this.stack.push(document.createElementNS($ns$, $element$))}"
         }
         fn create_placeholder(id: u32) {
-            "{node = document.createElement('pre'); node.hidden = true; stack.push(node); nodes[$id$] = node;}"
+            "{let node = document.createElement('pre'); node.hidden = true; this.stack.push(node); this.nodes[$id$] = node;}"
         }
         fn add_placeholder() {
-            "{node = document.createElement('pre'); node.hidden = true; stack.push(node);}"
+            "{let node = document.createElement('pre'); node.hidden = true; this.stack.push(node);}"
         }
         fn new_event_listener(event: &str<u8, evt>, id: u32, bubbles: u8) {
             r#"
             bubbles = bubbles == 1;
-            node = nodes[id];
+            let node = this.nodes[id];
             if(node.listening){
                 node.listening += 1;
             } else {
@@ -325,7 +331,7 @@ pub mod binary_protocol {
             // if this is a mounted listener, we send the event immediately
             if (event_name === "mounted") {
                 window.ipc.postMessage(
-                    window.interpreter.serializeIpcMessage("user_event", {
+                    this.serializeIpcMessage("user_event", {
                         name: event_name,
                         element: id,
                         data: null,
@@ -333,26 +339,26 @@ pub mod binary_protocol {
                     })
                 );
             } else {
-                listeners.create(event_name, node, bubbles, (event) => {
-                    handler(event, event_name, bubbles, config);
+                this.listeners.create(event_name, node, bubbles, (event) => {
+                    this.handler(event, event_name, bubbles);
                 });
             }"#
         }
         fn remove_event_listener(event_name: &str<u8, evt>, id: u32, bubbles: u8) {
-            "{node = nodes[$id$]; node.listening -= 1; node.removeAttribute('data-dioxus-id'); listeners.remove(node, $event_name$, $bubbles$);}"
+            "{let node = this.nodes[$id$]; node.listening -= 1; node.removeAttribute('data-dioxus-id'); this.listeners.remove(node, $event_name$, $bubbles$);}"
         }
         fn set_text(id: u32, text: &str) {
-            "{nodes[$id$].textContent = $text$;}"
+            "{this.nodes[$id$].textContent = $text$;}"
         }
         fn set_attribute(id: u32, field: &str<u8, attr>, value: &str, ns: &str<u8, ns_cache>) {
-            "{node = nodes[$id$]; setAttributeInner(node, $field$, $value$, $ns$);}"
+            "{let node = this.nodes[$id$]; this.setAttributeInner(node, $field$, $value$, $ns$);}"
         }
         fn set_top_attribute(field: &str<u8, attr>, value: &str, ns: &str<u8, ns_cache>) {
-            "{setAttributeInner(stack[stack.length-1], $field$, $value$, $ns$);}"
+            "{this.setAttributeInner(this.stack[this.stack.length-1], $field$, $value$, $ns$);}"
         }
         fn remove_attribute(id: u32, field: &str<u8, attr>, ns: &str<u8, ns_cache>) {
             r#"{
-                node = nodes[$id$];
+                let node = this.nodes[$id$];
                 if (!ns) {
                     switch (field) {
                         case "value":
@@ -379,29 +385,29 @@ pub mod binary_protocol {
             }"#
         }
         fn assign_id(array: &[u8], id: u32) {
-            "{nodes[$id$] = LoadChild($array$);}"
+            "{this.nodes[$id$] = this.LoadChild($array$);}"
         }
         fn hydrate_text(array: &[u8], value: &str, id: u32) {
             r#"{
-                node = LoadChild($array$);
-                if (node.nodeType == Node.TEXT_NODE) {
+                let node = this.LoadChild($array$);
+                if (node.nodeType == node.TEXT_NODE) {
                     node.textContent = value;
                 } else {
                     let text = document.createTextNode(value);
                     node.replaceWith(text);
                     node = text;
                 }
-                nodes[$id$] = node;
+                this.nodes[$id$] = node;
             }"#
         }
         fn replace_placeholder(array: &[u8], n: u16) {
-            "{els = stack.splice(stack.length - $n$); node = LoadChild($array$); node.replaceWith(...els);}"
+            "{let els = this.stack.splice(this.stack.length - $n$); let node = this.LoadChild($array$); node.replaceWith(...els);}"
         }
         fn load_template(tmpl_id: u16, index: u16, id: u32) {
-            "{node = templates[$tmpl_id$][$index$].cloneNode(true); nodes[$id$] = node; stack.push(node);}"
+            "{let node = this.templates[$tmpl_id$][$index$].cloneNode(true); this.nodes[$id$] = node; this.stack.push(node);}"
         }
         fn add_templates(tmpl_id: u16, len: u16) {
-            "{templates[$tmpl_id$] = stack.splice(stack.length-$len$);}"
+            "{this.templates[$tmpl_id$] = this.stack.splice(this.stack.length-$len$);}"
         }
     }
 }

+ 3 - 2
packages/liveview/src/main.js

@@ -1,4 +1,4 @@
-const config = new InterpreterConfig(false);
+const intercept_link_redirects = false;
 
 function main() {
   let root = window.document.getElementById("main");
@@ -9,6 +9,7 @@ function main() {
 
 class IPC {
   constructor(root) {
+    window.interpreter = new JSChannel();
     window.interpreter.initialize(root);
     const ws = new WebSocket(WS_ADDR);
     ws.binaryType = "arraybuffer";
@@ -34,7 +35,7 @@ class IPC {
       // The first byte tells the shim if this is a binary of text frame
       if (binaryFrame) {
         // binary frame
-        run_from_bytes(messageData);
+        window.interpreter.run_from_bytes(messageData);
       }
       else {
         // text frame

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

@@ -559,6 +559,7 @@ impl RouteEnum {
             #(#type_defs)*
 
             #[allow(non_camel_case_types)]
+            #[allow(clippy::derive_partial_eq_without_eq)]
             #[derive(Debug, PartialEq)]
             pub enum #match_error_name {
                 #(#error_variants),*

+ 1 - 0
packages/router-macro/src/segment.rs

@@ -309,6 +309,7 @@ pub(crate) fn create_error_type(
 
     quote! {
         #[allow(non_camel_case_types)]
+        #[allow(clippy::derive_partial_eq_without_eq)]
         #[derive(Debug, PartialEq)]
         pub enum #error_name {
             ExtraSegments(String),

+ 2 - 2
packages/signals/Cargo.toml

@@ -1,7 +1,7 @@
 [package]
 name = "dioxus-signals"
-authors = ["Jonathan Kelley"]
-version = "0.4.3"
+authors = ["Jonathan Kelley", "Evan Almloff"]
+version = { workspace = true }
 edition = "2021"
 description = "Signals for Dioxus"
 license = "MIT OR Apache-2.0"

+ 3 - 1
packages/signals/src/read.rs

@@ -39,7 +39,9 @@ pub trait Readable {
         MappedSignal::new(try_read, peek)
     }
 
-    /// Get the current value of the state. If this is a signal, this will subscribe the current scope to the signal. If the value has been dropped, this will panic.
+    /// Get the current value of the state. If this is a signal, this will subscribe the current scope to the signal.
+    /// If the value has been dropped, this will panic. Calling this on a Signal is the same as
+    /// using the signal() syntax to read and subscribe to its value
     #[track_caller]
     fn read(&self) -> ReadableRef<Self> {
         self.try_read().unwrap()

+ 1 - 1
packages/ssr/Cargo.toml

@@ -20,7 +20,7 @@ tracing = { workspace = true }
 http = { workspace = true }
 async-trait = { workspace = true }
 serde_json = { workspace = true }
-chrono = { verison = "0.4.34", optional = true }
+chrono = { version = "0.4.34", optional = true }
 
 [target.'cfg(target_arch = "wasm32")'.dependencies]
 tokio = { version = "1.28", features = ["io-util"], optional = true }

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

@@ -110,6 +110,7 @@ impl WebsysDom {
         }));
 
         dioxus_interpreter_js::initialize(
+            interpreter.js_channel(),
             root.clone().unchecked_into(),
             handler.as_ref().unchecked_ref(),
         );

+ 2 - 2
packages/web/src/mutations.rs

@@ -62,7 +62,7 @@ impl WebsysDom {
         // Now that we've flushed the edits and the dom nodes exist, we can send the mounted events.
         {
             for id in self.queued_mounted_events.drain(..) {
-                let node = get_node(id.0 as u32);
+                let node = get_node(self.interpreter.js_channel(), id.0 as u32);
                 if let Some(element) = node.dyn_ref::<web_sys::Element>() {
                     let _ = self.event_channel.unbounded_send(UiEvent {
                         name: "mounted".to_string(),
@@ -91,7 +91,7 @@ impl WriteMutations for WebsysDom {
 
         self.templates
             .insert(template.name.to_owned(), self.max_template_id);
-        save_template(roots, self.max_template_id);
+        save_template(self.interpreter.js_channel(), roots, self.max_template_id);
         self.max_template_id += 1
     }
 

+ 6 - 2
packages/web/src/rehydrate.rs

@@ -23,7 +23,7 @@ impl WebsysDom {
         // Recursively rehydrate the dom from the VirtualDom
         self.rehydrate_scope(root_scope, dom, &mut ids, &mut to_mount)?;
 
-        dioxus_interpreter_js::hydrate(ids);
+        dioxus_interpreter_js::hydrate(self.interpreter.js_channel(), ids);
 
         #[cfg(feature = "mounted")]
         for id in to_mount {
@@ -168,7 +168,11 @@ impl WriteMutations for OnlyWriteTemplates<'_> {
         self.0
             .templates
             .insert(template.name.to_owned(), self.0.max_template_id);
-        save_template(roots, self.0.max_template_id);
+        save_template(
+            self.0.interpreter.js_channel(),
+            roots,
+            self.0.max_template_id,
+        );
         self.0.max_template_id += 1
     }