Compare commits

...
7 Commits
Author SHA1 Message Date
Nico Burns 57d6794ad6 release v0.7.10 2026-07-30 15:33:31 -07:00
Nico Burns fda083bb65 Fix hotpatching when the bin target's crate name differs from the package name (#5719) (#5720)
(cherry picked from commit 4c51c12bc19d78983cb2992f319ebe996acb2893)

Signed-off-by: Nico Burns <nico@nicoburns.com>
2026-07-29 16:55:16 -07:00
Jonathan Kelley 3e43ffa6cf release v0.7.9 2026-05-07 17:09:43 -07:00
Jonathan Kelley bfcc111817 fix: git sha for cli 2026-05-07 16:59:46 -07:00
Jonathan Kelley d1ead872b1 fix: make instantiate async 2026-05-07 16:44:37 -07:00
Jonathan Kelley f5be0ea510 release v0.7.8 2026-05-07 15:28:20 -07:00
f1a0124227 backport iframe fix to v0.7 (#5535)
* feat:Add opt‑in navigation handler for external URLs (#5531)

* add navigation handler config option

code from https://github.com/DioxusLabs/dioxus/pull/5231

* Re-order branches

The branches should be reorder so that the branch that checks for
the index and assets is always taken first. Otherwise, they will
fail to load for users who forget to allow them in their custom
handlers, which will be a crappy experience and hard to debug.

* remove return

* Change behavior when handler not set

---------

Co-authored-by: not a cow <agielow@proton.me>

* fix: allow navigations but disallow external nav

---------

Co-authored-by: Martin Martinez Rivera <mrtnz.rvr@gmail.com>
Co-authored-by: not a cow <agielow@proton.me>
2026-05-07 15:11:47 -07:00
12 changed files with 340 additions and 168 deletions

No files matched your search

+12
View File
@@ -70,6 +70,18 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v5
with:
# Build from the tag we're releasing, not the branch the workflow
# was dispatched from. Without this the binary's Cargo.toml version
# and embedded SHA reflect whatever was on the dispatch branch.
ref: refs/tags/${{ github.event.inputs.post }}
- name: Resolve release commit SHA
shell: bash
run: |
sha=$(git rev-parse HEAD)
echo "DIOXUS_CLI_GIT_SHA=$sha" >> "$GITHUB_ENV"
echo "DIOXUS_CLI_GIT_SHA_SHORT=${sha:0:7}" >> "$GITHUB_ENV"
- name: Install openssl on macos
if: matrix.platform.os == 'macos-latest'
Generated
+56 -56
View File
@@ -3110,7 +3110,7 @@ dependencies = [
[[package]]
name = "depinfo"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"thiserror 2.0.18",
]
@@ -3246,7 +3246,7 @@ dependencies = [
[[package]]
name = "dioxus"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"criterion",
"dioxus",
@@ -3288,7 +3288,7 @@ dependencies = [
[[package]]
name = "dioxus-asset-resolver"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"dioxus",
"dioxus-cli-config",
@@ -3309,7 +3309,7 @@ dependencies = [
[[package]]
name = "dioxus-autofmt"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"dioxus-rsx",
"pretty_assertions",
@@ -3323,7 +3323,7 @@ dependencies = [
[[package]]
name = "dioxus-cli"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"ansi-to-html",
"ansi-to-tui",
@@ -3451,7 +3451,7 @@ dependencies = [
[[package]]
name = "dioxus-cli-config"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"wasm-bindgen",
]
@@ -3467,7 +3467,7 @@ dependencies = [
[[package]]
name = "dioxus-cli-telemetry"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"chrono",
"dirs",
@@ -3479,7 +3479,7 @@ dependencies = [
[[package]]
name = "dioxus-component-manifest"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"schemars 1.2.1",
"serde",
@@ -3488,7 +3488,7 @@ dependencies = [
[[package]]
name = "dioxus-config-macro"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"proc-macro2",
"quote",
@@ -3496,11 +3496,11 @@ dependencies = [
[[package]]
name = "dioxus-config-macros"
version = "0.7.7"
version = "0.7.10"
[[package]]
name = "dioxus-core"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"anyhow",
"const_format",
@@ -3531,7 +3531,7 @@ dependencies = [
[[package]]
name = "dioxus-core-macro"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"convert_case 0.8.0",
"dioxus",
@@ -3547,11 +3547,11 @@ dependencies = [
[[package]]
name = "dioxus-core-types"
version = "0.7.7"
version = "0.7.10"
[[package]]
name = "dioxus-desktop"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"anyhow",
"async-trait",
@@ -3612,7 +3612,7 @@ dependencies = [
[[package]]
name = "dioxus-devtools"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"dioxus-cli-config",
"dioxus-core",
@@ -3631,7 +3631,7 @@ dependencies = [
[[package]]
name = "dioxus-devtools-types"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"dioxus-core",
"serde",
@@ -3640,7 +3640,7 @@ dependencies = [
[[package]]
name = "dioxus-document"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"dioxus",
"dioxus-core",
@@ -3658,7 +3658,7 @@ dependencies = [
[[package]]
name = "dioxus-dx-wire-format"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"cargo_metadata",
"manganis-core",
@@ -3707,7 +3707,7 @@ dependencies = [
[[package]]
name = "dioxus-ext"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"dioxus-autofmt",
"dioxus-rsx-rosetta",
@@ -3718,7 +3718,7 @@ dependencies = [
[[package]]
name = "dioxus-fullstack"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"anyhow",
"async-stream",
@@ -3785,7 +3785,7 @@ dependencies = [
[[package]]
name = "dioxus-fullstack-core"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"anyhow",
"axum-core 0.5.6",
@@ -3813,7 +3813,7 @@ dependencies = [
[[package]]
name = "dioxus-fullstack-macro"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"axum 0.8.9",
"const_format",
@@ -3829,7 +3829,7 @@ dependencies = [
[[package]]
name = "dioxus-history"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"dioxus",
"dioxus-core",
@@ -3838,7 +3838,7 @@ dependencies = [
[[package]]
name = "dioxus-hooks"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"dioxus",
"dioxus-core",
@@ -3856,7 +3856,7 @@ dependencies = [
[[package]]
name = "dioxus-html"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"async-trait",
"bytes",
@@ -3887,7 +3887,7 @@ dependencies = [
[[package]]
name = "dioxus-html-internal-macro"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"convert_case 0.8.0",
"proc-macro2",
@@ -3898,7 +3898,7 @@ dependencies = [
[[package]]
name = "dioxus-interpreter-js"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"dioxus-core",
"dioxus-core-types",
@@ -3916,7 +3916,7 @@ dependencies = [
[[package]]
name = "dioxus-liveview"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"axum 0.8.9",
"dioxus",
@@ -3944,7 +3944,7 @@ dependencies = [
[[package]]
name = "dioxus-logger"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"dioxus",
"dioxus-cli-config",
@@ -3955,7 +3955,7 @@ dependencies = [
[[package]]
name = "dioxus-native"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"anyrender",
"anyrender_vello",
@@ -3990,7 +3990,7 @@ dependencies = [
[[package]]
name = "dioxus-native-dom"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"blitz-dom",
"blitz-traits",
@@ -4115,7 +4115,7 @@ dependencies = [
[[package]]
name = "dioxus-router"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"axum 0.8.9",
"base64 0.22.1",
@@ -4143,7 +4143,7 @@ dependencies = [
[[package]]
name = "dioxus-router-macro"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"base16",
"digest",
@@ -4157,7 +4157,7 @@ dependencies = [
[[package]]
name = "dioxus-rsx"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"prettier-please",
"prettyplease",
@@ -4170,7 +4170,7 @@ dependencies = [
[[package]]
name = "dioxus-rsx-hotreload"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"dioxus-core",
"dioxus-core-types",
@@ -4185,7 +4185,7 @@ dependencies = [
[[package]]
name = "dioxus-rsx-rosetta"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"convert_case 0.8.0",
"dioxus-autofmt",
@@ -4201,7 +4201,7 @@ dependencies = [
[[package]]
name = "dioxus-server"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"anyhow",
"async-trait",
@@ -4263,7 +4263,7 @@ dependencies = [
[[package]]
name = "dioxus-signals"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"dioxus",
"dioxus-core",
@@ -4283,7 +4283,7 @@ dependencies = [
[[package]]
name = "dioxus-ssr"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"askama_escape",
"dioxus",
@@ -4294,7 +4294,7 @@ dependencies = [
[[package]]
name = "dioxus-stores"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"dioxus",
"dioxus-core",
@@ -4305,7 +4305,7 @@ dependencies = [
[[package]]
name = "dioxus-stores-macro"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"convert_case 0.8.0",
"dioxus",
@@ -4325,7 +4325,7 @@ dependencies = [
[[package]]
name = "dioxus-web"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"ciborium",
"dioxus",
@@ -5468,7 +5468,7 @@ dependencies = [
[[package]]
name = "generational-box"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"criterion",
"parking_lot",
@@ -7885,7 +7885,7 @@ dependencies = [
[[package]]
name = "lazy-js-bundle"
version = "0.7.7"
version = "0.7.10"
[[package]]
name = "lazy_static"
@@ -8303,7 +8303,7 @@ dependencies = [
[[package]]
name = "manganis"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"const-serialize 0.7.2",
"const-serialize 0.8.0-alpha.0",
@@ -8317,7 +8317,7 @@ dependencies = [
[[package]]
name = "manganis-core"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"const-serialize 0.7.2",
"const-serialize 0.8.0-alpha.0",
@@ -8338,7 +8338,7 @@ dependencies = [
[[package]]
name = "manganis-macro"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"dunce",
"macro-string",
@@ -12547,7 +12547,7 @@ dependencies = [
[[package]]
name = "ssr-only"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"dioxus",
]
@@ -12815,7 +12815,7 @@ dependencies = [
[[package]]
name = "subsecond"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"js-sys",
"libc",
@@ -12841,7 +12841,7 @@ dependencies = [
[[package]]
name = "subsecond-types"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"serde",
]
@@ -12873,7 +12873,7 @@ dependencies = [
[[package]]
name = "suspense-carousel"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"async-std",
"dioxus",
@@ -14521,7 +14521,7 @@ dependencies = [
[[package]]
name = "wasm-split-cli"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"anyhow",
"clap",
@@ -14554,7 +14554,7 @@ dependencies = [
[[package]]
name = "wasm-split-macro"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"base16",
"digest",
@@ -14566,7 +14566,7 @@ dependencies = [
[[package]]
name = "wasm-splitter"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"async-once-cell",
"wasm-split-macro",
@@ -14587,7 +14587,7 @@ dependencies = [
[[package]]
name = "wasm-used"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"id-arena",
"tracing",
@@ -15351,7 +15351,7 @@ dependencies = [
[[package]]
name = "windows-headless"
version = "0.7.7"
version = "0.7.10"
dependencies = [
"dioxus",
]
+52 -52
View File
@@ -114,71 +114,71 @@ members = [
[workspace.package]
version = "0.7.7"
version = "0.7.10"
# dependencies that are shared across packages
[workspace.dependencies]
dioxus = { path = "packages/dioxus", version = "0.7.7" }
dioxus-core = { path = "packages/core", version = "0.7.7" }
dioxus-core-types = { path = "packages/core-types", version = "0.7.7" }
dioxus-core-macro = { path = "packages/core-macro", version = "0.7.7" }
dioxus-config-macro = { path = "packages/config-macro", version = "0.7.7" }
dioxus-router = { path = "packages/router", version = "0.7.7" }
dioxus-router-macro = { path = "packages/router-macro", version = "0.7.7" }
dioxus-document = { path = "packages/document", version = "0.7.7", default-features = false }
dioxus-history = { path = "packages/history", version = "0.7.7", default-features = false }
dioxus-html = { path = "packages/html", version = "0.7.7", default-features = false }
dioxus-html-internal-macro = { path = "packages/html-internal-macro", version = "0.7.7" }
dioxus-hooks = { path = "packages/hooks", version = "0.7.7" }
dioxus-web = { path = "packages/web", version = "0.7.7", default-features = false }
dioxus-ssr = { path = "packages/ssr", version = "0.7.7", default-features = false }
dioxus-desktop = { path = "packages/desktop", version = "0.7.7", default-features = false }
dioxus-interpreter-js = { path = "packages/interpreter", version = "0.7.7" }
dioxus-liveview = { path = "packages/liveview", version = "0.7.7" }
dioxus-autofmt = { path = "packages/autofmt", version = "0.7.7" }
dioxus-rsx = { path = "packages/rsx", version = "0.7.7" }
dioxus-rsx-hotreload = { path = "packages/rsx-hotreload", version = "0.7.7" }
dioxus-rsx-rosetta = { path = "packages/rsx-rosetta", version = "0.7.7" }
dioxus-signals = { path = "packages/signals", version = "0.7.7" }
dioxus-stores = { path = "packages/stores", version = "0.7.7" }
dioxus-stores-macro = { path = "packages/stores-macro", version = "0.7.7" }
dioxus-devtools = { path = "packages/devtools", version = "0.7.7" }
dioxus-devtools-types = { path = "packages/devtools-types", version = "0.7.7" }
dioxus-fullstack = { path = "packages/fullstack", version = "0.7.7", default-features = false }
dioxus-fullstack-core = { path = "packages/fullstack-core", version = "0.7.7", default-features = false }
dioxus-fullstack-macro = { path = "packages/fullstack-macro", version = "0.7.7", default-features = false }
dioxus-server = { path = "packages/fullstack-server", version = "0.7.7" }
dioxus-dx-wire-format = { path = "packages/dx-wire-format", version = "0.7.7" }
dioxus-logger = { path = "packages/logger", version = "0.7.7" }
dioxus-native = { path = "packages/native", version = "0.7.7" }
dioxus-native-dom = { path = "packages/native-dom", version = "0.7.7" }
dioxus-asset-resolver = { path = "packages/asset-resolver", version = "0.7.7" }
dioxus-config-macros = { path = "packages/config-macros", version = "0.7.7" }
dioxus-component-manifest = { path = "packages/component-manifest", version = "0.7.7" }
generational-box = { path = "packages/generational-box", version = "0.7.7" }
lazy-js-bundle = { path = "packages/lazy-js-bundle", version = "0.7.7" }
dioxus = { path = "packages/dioxus", version = "0.7.10" }
dioxus-core = { path = "packages/core", version = "0.7.10" }
dioxus-core-types = { path = "packages/core-types", version = "0.7.10" }
dioxus-core-macro = { path = "packages/core-macro", version = "0.7.10" }
dioxus-config-macro = { path = "packages/config-macro", version = "0.7.10" }
dioxus-router = { path = "packages/router", version = "0.7.10" }
dioxus-router-macro = { path = "packages/router-macro", version = "0.7.10" }
dioxus-document = { path = "packages/document", version = "0.7.10", default-features = false }
dioxus-history = { path = "packages/history", version = "0.7.10", default-features = false }
dioxus-html = { path = "packages/html", version = "0.7.10", default-features = false }
dioxus-html-internal-macro = { path = "packages/html-internal-macro", version = "0.7.10" }
dioxus-hooks = { path = "packages/hooks", version = "0.7.10" }
dioxus-web = { path = "packages/web", version = "0.7.10", default-features = false }
dioxus-ssr = { path = "packages/ssr", version = "0.7.10", default-features = false }
dioxus-desktop = { path = "packages/desktop", version = "0.7.10", default-features = false }
dioxus-interpreter-js = { path = "packages/interpreter", version = "0.7.10" }
dioxus-liveview = { path = "packages/liveview", version = "0.7.10" }
dioxus-autofmt = { path = "packages/autofmt", version = "0.7.10" }
dioxus-rsx = { path = "packages/rsx", version = "0.7.10" }
dioxus-rsx-hotreload = { path = "packages/rsx-hotreload", version = "0.7.10" }
dioxus-rsx-rosetta = { path = "packages/rsx-rosetta", version = "0.7.10" }
dioxus-signals = { path = "packages/signals", version = "0.7.10" }
dioxus-stores = { path = "packages/stores", version = "0.7.10" }
dioxus-stores-macro = { path = "packages/stores-macro", version = "0.7.10" }
dioxus-devtools = { path = "packages/devtools", version = "0.7.10" }
dioxus-devtools-types = { path = "packages/devtools-types", version = "0.7.10" }
dioxus-fullstack = { path = "packages/fullstack", version = "0.7.10", default-features = false }
dioxus-fullstack-core = { path = "packages/fullstack-core", version = "0.7.10", default-features = false }
dioxus-fullstack-macro = { path = "packages/fullstack-macro", version = "0.7.10", default-features = false }
dioxus-server = { path = "packages/fullstack-server", version = "0.7.10" }
dioxus-dx-wire-format = { path = "packages/dx-wire-format", version = "0.7.10" }
dioxus-logger = { path = "packages/logger", version = "0.7.10" }
dioxus-native = { path = "packages/native", version = "0.7.10" }
dioxus-native-dom = { path = "packages/native-dom", version = "0.7.10" }
dioxus-asset-resolver = { path = "packages/asset-resolver", version = "0.7.10" }
dioxus-config-macros = { path = "packages/config-macros", version = "0.7.10" }
dioxus-component-manifest = { path = "packages/component-manifest", version = "0.7.10" }
generational-box = { path = "packages/generational-box", version = "0.7.10" }
lazy-js-bundle = { path = "packages/lazy-js-bundle", version = "0.7.10" }
# cli
dioxus-cli-telemetry = { path = "packages/cli-telemetry", version = "0.7.7" }
dioxus-cli-config = { path = "packages/cli-config", version = "0.7.7" }
dioxus-cli-telemetry = { path = "packages/cli-telemetry", version = "0.7.10" }
dioxus-cli-config = { path = "packages/cli-config", version = "0.7.10" }
# subsecond
subsecond-types = { path = "packages/subsecond/subsecond-types", version = "0.7.7" }
subsecond = { path = "packages/subsecond/subsecond", version = "0.7.7" }
subsecond-types = { path = "packages/subsecond/subsecond-types", version = "0.7.10" }
subsecond = { path = "packages/subsecond/subsecond", version = "0.7.10" }
# wasm-split
wasm-splitter = { path = "packages/wasm-split/wasm-split", version = "0.7.7" }
wasm-split-macro = { path = "packages/wasm-split/wasm-split-macro", version = "0.7.7" }
wasm-split-cli = { path = "packages/wasm-split/wasm-split-cli", version = "0.7.7" }
wasm-used = { path = "packages/wasm-split/wasm-used", version = "0.7.7" }
wasm-splitter = { path = "packages/wasm-split/wasm-split", version = "0.7.10" }
wasm-split-macro = { path = "packages/wasm-split/wasm-split-macro", version = "0.7.10" }
wasm-split-cli = { path = "packages/wasm-split/wasm-split-cli", version = "0.7.10" }
wasm-used = { path = "packages/wasm-split/wasm-used", version = "0.7.10" }
# our dep-info parsing crate
depinfo = { path = "packages/depinfo", version = "0.7.7" }
depinfo = { path = "packages/depinfo", version = "0.7.10" }
# manganis
manganis = { path = "packages/manganis/manganis", version = "0.7.7" }
manganis-core = { path = "packages/manganis/manganis-core", version = "0.7.7" }
manganis-macro = { path = "packages/manganis/manganis-macro", version = "0.7.7" }
manganis = { path = "packages/manganis/manganis", version = "0.7.10" }
manganis-core = { path = "packages/manganis/manganis-core", version = "0.7.10" }
manganis-macro = { path = "packages/manganis/manganis-macro", version = "0.7.10" }
manganis-core-07 = { path = "packages/manganis/manganis-07", version = "0.7.2" }
# const-serialize.
+11 -4
View File
@@ -98,12 +98,19 @@
);
in
{
packages.dioxus-cli = (
rustPackage "dioxus-cli" {
packages.dioxus-cli =
(rustPackage "dioxus-cli" {
binary = "dx";
features = [ "no-downloads" ];
}
);
}).overrideAttrs
(_: {
# The nix sandbox has no .git and no .cargo_vcs_info.json, so
# build.rs has nothing to derive the commit from. Pass the
# flake's own input rev through the env-var override path.
# `self.rev` is set on a clean tree; `dirtyRev` on a dirty one
# (and includes a `-dirty` suffix, which build.rs accepts).
DIOXUS_CLI_GIT_SHA = inputs.self.rev or inputs.self.dirtyRev or "";
});
packages.default = self'.packages.dioxus-cli;
checks.dioxus-cli = self'.packages.dioxus-cli;
+128 -21
View File
@@ -1,38 +1,145 @@
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;
fn main() {
println!("cargo:rerun-if-env-changed=DIOXUS_CLI_GIT_SHA");
println!("cargo:rerun-if-env-changed=DIOXUS_CLI_GIT_SHA_SHORT");
println!("cargo:rerun-if-changed=.git/HEAD");
println!("cargo:rerun-if-changed=.git/refs");
let full_hash = std::env::var("DIOXUS_CLI_GIT_SHA").ok().or_else(|| {
let output = Command::new("git")
.args(["rev-parse", "HEAD"])
.output()
.ok()?;
let manifest_dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
let git_dir = find_git_dir(&manifest_dir);
if !output.status.success() {
return None;
// Track the files that determine the current commit. Absolute paths are
// required because the build script runs from `packages/cli/`, not the
// workspace root where `.git` lives.
if let Some(git_dir) = git_dir.as_deref() {
emit_rerun(&git_dir.join("HEAD"));
emit_rerun(&git_dir.join("packed-refs"));
if let Some(target) = head_ref_target(git_dir) {
emit_rerun(&git_dir.join(target));
}
}
emit_rerun(&manifest_dir.join(".cargo_vcs_info.json"));
let hash = String::from_utf8(output.stdout).ok()?;
let hash = hash.trim().to_string();
if hash.is_empty() {
None
} else {
Some(hash)
}
});
let full_hash = env_nonempty("DIOXUS_CLI_GIT_SHA")
.or_else(|| git_dir.as_deref().and_then(read_head_sha))
.or_else(|| read_cargo_vcs_info(&manifest_dir))
.or_else(|| git_cli_sha(&manifest_dir));
if let Some(full_hash) = full_hash {
let full_hash = full_hash.trim();
println!("cargo:rustc-env=DIOXUS_CLI_GIT_SHA={full_hash}");
let short_hash = std::env::var("DIOXUS_CLI_GIT_SHA_SHORT")
.ok()
let short_hash = env_nonempty("DIOXUS_CLI_GIT_SHA_SHORT")
.unwrap_or_else(|| full_hash.chars().take(7).collect());
println!("cargo:rustc-env=DIOXUS_CLI_GIT_SHA_SHORT={short_hash}");
}
}
fn env_nonempty(key: &str) -> Option<String> {
env::var(key).ok().filter(|s| !s.trim().is_empty())
}
fn emit_rerun(path: &Path) {
println!("cargo:rerun-if-changed={}", path.display());
}
/// Walk up from `start` looking for `.git`. Handles the file form used by
/// git worktrees and submodules, where `.git` contains `gitdir: <path>`.
fn find_git_dir(start: &Path) -> Option<PathBuf> {
for dir in start.ancestors() {
let candidate = dir.join(".git");
let meta = match fs::metadata(&candidate) {
Ok(m) => m,
Err(_) => continue,
};
if meta.is_dir() {
return Some(candidate);
}
if meta.is_file() {
let contents = fs::read_to_string(&candidate).ok()?;
let pointer = contents
.lines()
.find_map(|l| l.strip_prefix("gitdir:"))?
.trim();
let resolved = if Path::new(pointer).is_absolute() {
PathBuf::from(pointer)
} else {
dir.join(pointer)
};
return Some(resolved);
}
}
None
}
/// If HEAD is a symbolic ref (`ref: refs/heads/foo`), return the target path.
fn head_ref_target(git_dir: &Path) -> Option<String> {
let head = fs::read_to_string(git_dir.join("HEAD")).ok()?;
head.strip_prefix("ref:").map(|s| s.trim().to_owned())
}
fn read_head_sha(git_dir: &Path) -> Option<String> {
let head = fs::read_to_string(git_dir.join("HEAD")).ok()?;
let head = head.trim();
let Some(target) = head.strip_prefix("ref:").map(str::trim) else {
// Detached HEAD: the file holds the SHA directly.
return is_sha(head).then(|| head.to_owned());
};
// Loose ref file.
if let Ok(sha) = fs::read_to_string(git_dir.join(target)) {
let sha = sha.trim();
if is_sha(sha) {
return Some(sha.to_owned());
}
}
// Packed refs (after `git gc` / shallow clones, refs only live here).
let packed = fs::read_to_string(git_dir.join("packed-refs")).ok()?;
for line in packed.lines() {
if line.starts_with('#') || line.starts_with('^') || line.is_empty() {
continue;
}
let (sha, name) = line.split_once(' ')?;
if name == target && is_sha(sha) {
return Some(sha.to_owned());
}
}
None
}
/// Cargo writes `.cargo_vcs_info.json` next to `Cargo.toml` when publishing,
/// recording the source SHA at publish time. This is how `cargo install`
/// from crates.io can still report a real commit despite the `.crate`
/// tarball having no `.git/`.
fn read_cargo_vcs_info(manifest_dir: &Path) -> Option<String> {
let contents = fs::read_to_string(manifest_dir.join(".cargo_vcs_info.json")).ok()?;
// Cheap targeted parse so we don't pull serde into the build script.
// The file is generated by cargo and the field name is stable.
let after = contents.split("\"sha1\"").nth(1)?;
let sha = after.split('"').nth(1)?.trim();
is_sha(sha).then(|| sha.to_owned())
}
fn git_cli_sha(manifest_dir: &Path) -> Option<String> {
// Scope `git` to the manifest dir so we never accidentally pick up a
// SHA from a parent repo (e.g. someone's `~` is a git repo).
let output = Command::new("git")
.arg("-C")
.arg(manifest_dir)
.args(["rev-parse", "HEAD"])
.output()
.ok()?;
if !output.status.success() {
return None;
}
let sha = String::from_utf8(output.stdout).ok()?.trim().to_owned();
is_sha(&sha).then_some(sha)
}
fn is_sha(s: &str) -> bool {
matches!(s.len(), 40 | 64) && s.chars().all(|c| c.is_ascii_hexdigit())
}
+3 -1
View File
@@ -408,7 +408,9 @@ impl AppBuilder {
// patch (starting from changed_crates + cascade). That serves a different purpose — it only
// compiles what changed now, not everything ever modified. Both use workspace_dependents_of
// for the BFS, so they stay in sync automatically.
let tip_crate_name = self.build.main_target.replace('-', "_");
// Track the tip by *package* name — that's the identity used by the file→crate
// mapping and the workspace dependents graph (the bin target name can differ).
let tip_crate_name = self.build.tip_package_name();
self.modified_crates.insert(tip_crate_name.clone());
// Add changed crates and their transitive workspace dependents (cascade).
+3 -1
View File
@@ -614,7 +614,9 @@ impl BuildRequest {
modified_crates: &HashSet<String>,
) -> Result<Vec<String>> {
// Exclude the tip crate — it's compiled separately via cargo_build after replay.
let tip = self.tip_crate_name();
// Modified crates are tracked by *package* name, which can differ from the bin
// target name (`tip_crate_name()`), e.g. package `browser` with `[[bin]] name = "blitz"`.
let tip = self.tip_package_name();
let crates: HashSet<&String> = modified_crates
.iter()
.filter(|name| **name != tip)
+11 -1
View File
@@ -2581,6 +2581,16 @@ impl BuildRequest {
self.main_target.replace('-', "_")
}
/// The workspace package name of the tip crate (hyphens replaced with underscores).
///
/// This can differ from `tip_crate_name()` when the binary target is named differently
/// than its package (e.g. package `browser` with `[[bin]] name = "blitz"`). Use this for
/// workspace-graph lookups (which are keyed by package name) and `tip_crate_name()` for
/// rustc `--crate-name` keys like `{name}.bin`.
pub(crate) fn tip_package_name(&self) -> String {
self.package().name.replace('-', "_")
}
/// Stderr captured from the linker during the last build. Written by the linker
/// interception in `rustcwrapper` and read back to surface warnings/errors to the user.
fn link_err_file(&self) -> PathBuf {
@@ -3095,7 +3105,7 @@ impl BuildRequest {
})
.collect();
let tip = self.tip_crate_name();
let tip = self.tip_package_name();
let Some(tip_nid) = krates.workspace_members().find_map(|m| match m {
krates::Node::Krate { id, krate, .. } if krate.name.replace('-', "_") == tip => {
krates.nid_for_kid(id)
+1 -1
View File
@@ -1187,7 +1187,7 @@ impl AppServer {
/// Uses BFS from the tip crate through its workspace dependencies to find the path.
/// If the changed crate IS the tip crate, returns just `[tip]`.
pub(crate) fn workspace_dep_chain(&self, changed_crate: &str) -> Vec<String> {
let tip_name = self.client.build.main_target.replace('-', "_");
let tip_name = self.client.build.tip_package_name();
// If the changed crate is the tip, no chain needed
if changed_crate == tip_name {
+13
View File
@@ -20,6 +20,10 @@ type CustomEventHandler = Box<
),
>;
/// A function taking a URL and returning whether the webview should navigate to it or open it in
/// the browser. If missing in the config, all URLs will be allowed.
type NavigationHandler = Box<dyn Fn(&str) -> bool + 'static>;
/// The closing behaviour of specific application window.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[non_exhaustive]
@@ -70,6 +74,7 @@ pub struct Config {
pub(crate) disable_dma_buf_on_wayland: bool,
pub(crate) additional_windows_args: Option<String>,
pub(crate) tray_icon_show_window_on_click: bool,
pub(crate) navigation_handler: Option<NavigationHandler>,
#[allow(clippy::type_complexity)]
pub(crate) on_window: Option<Box<dyn FnMut(Arc<Window>, &mut VirtualDom) + 'static>>,
@@ -124,6 +129,7 @@ impl Config {
on_window: None,
additional_windows_args: None,
tray_icon_show_window_on_click: true,
navigation_handler: None,
}
}
@@ -350,6 +356,13 @@ impl Config {
self.tray_icon_show_window_on_click = show;
self
}
/// Set a custom navigation handler for non-dioxus URLs.
/// Return true to allow navigation inside the webview, false to block.
pub fn with_navigation_handler(mut self, f: impl Fn(&str) -> bool + 'static) -> Self {
self.navigation_handler = Some(Box::new(f));
self
}
}
impl Default for Config {
+17 -12
View File
@@ -353,6 +353,7 @@ impl WebviewInstance {
}
};
let navigation_handler = cfg.navigation_handler.take();
let page_loaded = AtomicBool::new(false);
let mut webview = WebViewBuilder::new_with_web_context(&mut web_context)
@@ -367,25 +368,29 @@ impl WebviewInstance {
.with_url("dioxus://index.html/")
.with_ipc_handler(ipc_handler)
.with_navigation_handler(move |var| {
// We don't want to allow any navigation
// We only want to serve the index file and assets
// Serve the index and assets.
if var.starts_with("dioxus://")
|| var.starts_with("http://dioxus.")
|| var.starts_with("https://dioxus.")
{
// After the page has loaded once, don't allow any more navigation
let page_loaded = page_loaded.swap(true, std::sync::atomic::Ordering::SeqCst);
!page_loaded
} else {
if var.starts_with("http://")
|| var.starts_with("https://")
|| var.starts_with("mailto:")
{
_ = webbrowser::open(&var);
}
false
return !page_loaded;
}
}) // prevent all navigations
// External links always open somewhere else. Prevents the webview from navigating
if var.starts_with("http://")
|| var.starts_with("https://")
|| var.starts_with("mailto:")
{
_ = webbrowser::open(&var);
return false;
}
// By default, external links are allowed. This keeps things like iframes working.
// However, users can customize this to allow/disallow domains/routes/patterns.
navigation_handler.as_ref().map(|f| f(&var)).unwrap_or(true)
})
.with_asynchronous_custom_protocol(String::from("dioxus"), request_handler);
// Enable https scheme on android, needed for secure context API, like the geolocation API
+33 -19
View File
@@ -594,24 +594,31 @@ pub unsafe fn apply_patch(mut table: JumpTable) -> Result<(), PatchError> {
.unwrap()
.unchecked_into();
// ── SYNC SECTION — no `.await` past this point ────────────────
// ── HOST-STATE-MUTATING SECTION ───────────────────────────────
//
// Everything below mutates shared JS state (linear memory, the
// indirect function table, the patch's data segment) and the
// jump-table pointer. We must not yield, because:
// Below we grow shared linear memory and the indirect function
// table, then async-instantiate the patch into them and commit
// the new jump table. There IS one `.await` for the instantiate
// (we can't avoid it: Chrome disallows synchronous
// `new WebAssembly.Instance` on the main thread for modules
// larger than 8MB, and patches routinely cross that), but it's
// safe — the original race we fixed wasn't about yielding here:
//
// * `memory.grow` detaches the previous `ArrayBuffer`. The old
// code captured `memory.buffer()` BEFORE the awaits and then
// read its `byteLength` to compute `__memory_base`; if any
// other task ran a `memory.grow` during the awaits (e.g. an
// allocator call from a concurrent render), the snapshot was
// detached, `byteLength` returned 0, and the patch's data
// segment ended up loaded over the host's stack/rodata.
// * Two concurrent `apply_patch` tasks must not interleave
// between memory/table grow and `commit_patch`. Doing all
// side-effecting work in one synchronous turn guarantees that.
// * If the future is cancelled before this point, host state
// is untouched.
// * `memory.grow` and `funcs.grow` each return their PRIOR
// length atomically. Concurrent `apply_patch` tasks therefore
// each get a unique, non-overlapping `memory_base` /
// `table_base`, so two patches can't land on the same region.
// * Host code can't observe the half-instantiated patch: the
// new memory pages are zero, the new table slots are null,
// and the jump table isn't committed until the very end of
// this block, so nothing redirects through the new slots.
// * The original bug — using `memory.buffer().byteLength()`
// captured before the awaits, which returned 0 if the buffer
// had been detached by a concurrent grow — is gone because
// we derive `memory_base` from `memory.grow()`'s return
// value instead.
// * Cancellation between grow and `commit_patch` leaks memory
// pages and table slots, but doesn't corrupt anything.
const PAGE_SIZE: u32 = 64 * 1024;
let patch_pages = (dl_bytes.byte_length() as f64 / PAGE_SIZE as f64).ceil() as u32 + 1;
@@ -646,9 +653,16 @@ pub unsafe fn apply_patch(mut table: JumpTable) -> Result<(), PatchError> {
let imports = Object::new();
Reflect::set(&imports, &"env".into(), &env).unwrap();
// Synchronous instantiation of the precompiled module — writes
// the patch's data segment into memory at `memory_base`.
let instance = Instance::new(&module, &imports).unwrap();
// Async instantiation of the precompiled module. We use the
// (Module, imports) form of `WebAssembly.instantiate`, which
// resolves directly to an `Instance` (not `{module, instance}`).
// This is the no-size-limit path; the synchronous
// `new WebAssembly.Instance` constructor is capped at 8MB on
// Chrome's main thread.
let instance: Instance = JsFuture::from(WebAssembly::instantiate_module(&module, &imports))
.await
.unwrap()
.unchecked_into();
let inst_exports: Object = instance.exports();
// Run the patch's relocation thunks and constructors. Order