diff --git a/.github/install.ps1 b/.github/install.ps1 new file mode 100644 index 000000000..685378e6f --- /dev/null +++ b/.github/install.ps1 @@ -0,0 +1,56 @@ +#!/usr/bin/env pwsh + +$ErrorActionPreference = 'Stop' + +if ($v) { + $Version = "v${v}" +} +if ($Args.Length -eq 1) { + $Version = $Args.Get(0) +} + +$DxInstall = $env:DX_INSTALL +$BinDir = if ($DxInstall) { + "${DxInstall}\bin" +} else { + "${Home}\.dx\bin" +} + +$DxZip = "$BinDir\dx.zip" +$DxExe = "$BinDir\dx.exe" +$Target = 'x86_64-pc-windows-msvc' + +$DownloadUrl = if (!$Version) { + "https://github.com/dioxuslabs/dioxus/releases/latest/download/dx-${target}.zip" +} else { + "https://github.com/dioxuslabs/dioxus/releases/download/${Version}/dx-${target}.zip" +} + + +if (!(Test-Path $BinDir)) { + New-Item $BinDir -ItemType Directory | Out-Null +} + +curl.exe --ssl-revoke-best-effort -Lo $DxZip $DownloadUrl + +tar.exe xf $DxZip -C $BinDir + +Remove-Item $DxZip + +$CargoBin = "${Home}\.cargo\bin" + +if (!(Test-Path $CargoBin)) { + New-Item $CargoBin -ItemType Directory | Out-Null +} + +Copy-Item $DxExe "$CargoBin\dx.exe" -Force + +# $User = [System.EnvironmentVariableTarget]::User +# $Path = [System.Environment]::GetEnvironmentVariable('Path', $User) +# if (!(";${Path};".ToLower() -like "*;${BinDir};*".ToLower())) { +# [System.Environment]::SetEnvironmentVariable('Path', "${Path};${BinDir}", $User) +# $Env:Path += ";${BinDir}" +# } + +Write-Output "dx was installed successfully! 💫" +Write-Output "Run 'dx --help' to get started" diff --git a/.github/install.sh b/.github/install.sh new file mode 100755 index 000000000..a16c7b126 --- /dev/null +++ b/.github/install.sh @@ -0,0 +1,104 @@ +#!/bin/sh +set -eo pipefail + +# Reset +Color_Off='' + +# Regular Colors +Red='' +Green='' +Dim='' # White + +# Bold +Bold_White='' +Bold_Green='' + +if [[ -t 1 ]]; then + # Reset + Color_Off='\033[0m' # Text Reset + + # Regular Colors + Red='\033[0;31m' # Red + Green='\033[0;32m' # Green + Dim='\033[0;2m' # White + + # Bold + Bold_Green='\033[1;32m' # Bold Green + Bold_White='\033[1m' # Bold White +fi + +error() { + echo -e "${Red}error${Color_Off}:" "$@" >&2 + exit 1 +} + +info() { + echo -e "${Dim}$@ ${Color_Off}" +} + +info_bold() { + echo -e "${Bold_White}$@ ${Color_Off}" +} + +success() { + echo -e "${Green}$@ ${Color_Off}" +} + +command -v unzip >/dev/null || + error 'unzip is required to install dx' + +if [[ $# -gt 1 ]]; then + error 'Too many arguments, only 1 are allowed. The first can be a specific tag of dx to install. (e.g. "dx-v0.7.1")' +fi + +if [ "$OS" = "Windows_NT" ]; then + target="x86_64-pc-windows-msvc" +else + case $(uname -sm) in + "Darwin x86_64") target="x86_64-apple-darwin" ;; + "Darwin arm64") target="aarch64-apple-darwin" ;; + "Linux aarch64") target="aarch64-unknown-linux-gnu" ;; + *) target="x86_64-unknown-linux-gnu" ;; + esac +fi + +GITHUB=${GITHUB-"https://github.com"} +github_repo="$GITHUB/dioxuslabs/dioxus" +exe_name=dx + +if [[ $# = 0 ]]; then + dx_uri=$github_repo/releases/latest/download/dx-$target.zip +else + dx_uri=$github_repo/releases/download/$1/dx-$target.zip +fi + +dx_install="${DX_INSTALL:-$HOME/.dx}" +bin_dir="$dx_install/bin" +exe="$bin_dir/dx" +cargo_bin_dir="$HOME/.cargo/bin" +cargo_bin_exe="$cargo_bin_dir/dx" + +if [ ! -d "$bin_dir" ]; then + mkdir -p "$bin_dir" +fi + +curl --fail --location --progress-bar --output "$exe.zip" "$dx_uri" +if command -v unzip >/dev/null; then + unzip -d "$bin_dir" -o "$exe.zip" +else + 7z x -o"$bin_dir" -y "$exe.zip" +fi +chmod +x "$exe" +cp "$exe" "$cargo_bin_exe" || error "Failed to copy dx to $cargo_bin_dir" +rm "$exe.zip" +echo " installed: $cargo_bin_exe" + +echo +echo "dx was installed successfully! 💫" +echo + +if command -v dx >/dev/null; then + echo "Run 'dx --help' to get started" +else + echo "Run '$exe --help' to get started" +fi diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 6d78ca242..9ba70dd15 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -98,7 +98,7 @@ jobs: bin: dx token: ${{ secrets.GITHUB_TOKEN }} target: ${{ matrix.platform.target }} - archive: $bin-$target-${{ env.RELEASE_TAG }} + archive: $bin-$target checksum: sha256 manifest_path: packages/cli/Cargo.toml ref: refs/tags/${{ env.RELEASE_POST }} diff --git a/Cargo.lock b/Cargo.lock index 5e4890595..4c7ebc101 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2624,7 +2624,7 @@ dependencies = [ [[package]] name = "const-serialize" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "const-serialize", "const-serialize-macro", @@ -2634,7 +2634,7 @@ dependencies = [ [[package]] name = "const-serialize-macro" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "proc-macro2", "quote", @@ -3398,7 +3398,7 @@ dependencies = [ [[package]] name = "depinfo" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "thiserror 2.0.12", ] @@ -3569,7 +3569,7 @@ dependencies = [ [[package]] name = "dioxus" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "criterion", "dioxus", @@ -3610,7 +3610,7 @@ dependencies = [ [[package]] name = "dioxus-asset-resolver" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "dioxus-cli-config", "http 1.3.1", @@ -3625,7 +3625,7 @@ dependencies = [ [[package]] name = "dioxus-autofmt" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "dioxus-rsx", "pretty_assertions", @@ -3638,7 +3638,7 @@ dependencies = [ [[package]] name = "dioxus-check" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "indoc", "owo-colors", @@ -3650,7 +3650,7 @@ dependencies = [ [[package]] name = "dioxus-cli" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "ansi-to-html", "ansi-to-tui", @@ -3725,6 +3725,8 @@ dependencies = [ "regex", "reqwest 0.12.15", "rustls 0.23.27", + "self-replace", + "self_update", "serde", "serde_json", "shell-words", @@ -3762,14 +3764,14 @@ dependencies = [ [[package]] name = "dioxus-cli-config" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "wasm-bindgen", ] [[package]] name = "dioxus-cli-opt" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "anyhow", "browserslist-rs 0.16.0", @@ -3828,7 +3830,7 @@ dependencies = [ [[package]] name = "dioxus-config-macro" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "proc-macro2", "quote", @@ -3836,11 +3838,11 @@ dependencies = [ [[package]] name = "dioxus-config-macros" -version = "0.6.3" +version = "0.7.0-alpha.0" [[package]] name = "dioxus-core" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "const_format", "dioxus", @@ -3871,7 +3873,7 @@ dependencies = [ [[package]] name = "dioxus-core-macro" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "convert_case 0.8.0", "dioxus", @@ -3887,14 +3889,14 @@ dependencies = [ [[package]] name = "dioxus-core-types" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "once_cell", ] [[package]] name = "dioxus-desktop" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "async-trait", "base64 0.22.1", @@ -3922,6 +3924,7 @@ dependencies = [ "infer", "jni", "lazy-js-bundle", + "libc", "muda 0.16.1", "ndk", "ndk-context", @@ -3951,7 +3954,7 @@ dependencies = [ [[package]] name = "dioxus-devtools" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "dioxus-cli-config", "dioxus-core", @@ -3969,7 +3972,7 @@ dependencies = [ [[package]] name = "dioxus-devtools-types" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "dioxus-core", "serde", @@ -3978,7 +3981,7 @@ dependencies = [ [[package]] name = "dioxus-document" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "dioxus", "dioxus-core", @@ -3996,7 +3999,7 @@ dependencies = [ [[package]] name = "dioxus-dx-wire-format" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "cargo_metadata", "serde", @@ -4005,7 +4008,7 @@ dependencies = [ [[package]] name = "dioxus-examples" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "async-std", "base64 0.22.1", @@ -4031,7 +4034,7 @@ dependencies = [ [[package]] name = "dioxus-ext" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "dioxus-autofmt", "dioxus-rsx-rosetta", @@ -4042,7 +4045,7 @@ dependencies = [ [[package]] name = "dioxus-fullstack" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "async-trait", "aws-lc-rs", @@ -4088,7 +4091,7 @@ dependencies = [ [[package]] name = "dioxus-fullstack-hooks" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "dioxus", "dioxus-core", @@ -4103,7 +4106,7 @@ dependencies = [ [[package]] name = "dioxus-fullstack-protocol" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "base64 0.22.1", "ciborium", @@ -4114,7 +4117,7 @@ dependencies = [ [[package]] name = "dioxus-history" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "dioxus", "dioxus-core", @@ -4123,7 +4126,7 @@ dependencies = [ [[package]] name = "dioxus-hooks" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "dioxus", "dioxus-core", @@ -4142,7 +4145,7 @@ dependencies = [ [[package]] name = "dioxus-html" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "async-trait", "dioxus", @@ -4171,7 +4174,7 @@ dependencies = [ [[package]] name = "dioxus-html-internal-macro" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "convert_case 0.8.0", "proc-macro2", @@ -4182,7 +4185,7 @@ dependencies = [ [[package]] name = "dioxus-interpreter-js" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "dioxus-core", "dioxus-core-types", @@ -4200,7 +4203,7 @@ dependencies = [ [[package]] name = "dioxus-isrg" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "chrono", "http 1.3.1", @@ -4213,7 +4216,7 @@ dependencies = [ [[package]] name = "dioxus-lib" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "dioxus", "dioxus-config-macro", @@ -4230,7 +4233,7 @@ dependencies = [ [[package]] name = "dioxus-liveview" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "axum 0.8.4", "dioxus", @@ -4258,7 +4261,7 @@ dependencies = [ [[package]] name = "dioxus-logger" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "console_error_panic_hook", "dioxus", @@ -4270,7 +4273,7 @@ dependencies = [ [[package]] name = "dioxus-mobile" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "dioxus-cli-config", "dioxus-desktop", @@ -4282,7 +4285,7 @@ dependencies = [ [[package]] name = "dioxus-native" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "blitz-dom", "blitz-net", @@ -4377,7 +4380,7 @@ dependencies = [ [[package]] name = "dioxus-router" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "axum 0.8.4", "base64 0.22.1", @@ -4400,7 +4403,7 @@ dependencies = [ [[package]] name = "dioxus-router-macro" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "base16", "digest", @@ -4414,7 +4417,7 @@ dependencies = [ [[package]] name = "dioxus-rsx" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "prettier-please", "prettyplease", @@ -4426,7 +4429,7 @@ dependencies = [ [[package]] name = "dioxus-rsx-hotreload" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "dioxus-core", "dioxus-core-types", @@ -4441,7 +4444,7 @@ dependencies = [ [[package]] name = "dioxus-rsx-rosetta" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "convert_case 0.8.0", "dioxus-autofmt", @@ -4457,7 +4460,7 @@ dependencies = [ [[package]] name = "dioxus-server" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "async-trait", "aws-lc-rs", @@ -4507,7 +4510,7 @@ dependencies = [ [[package]] name = "dioxus-signals" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "dioxus", "dioxus-core", @@ -4528,7 +4531,7 @@ dependencies = [ [[package]] name = "dioxus-ssr" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "askama_escape", "dioxus", @@ -4547,7 +4550,7 @@ dependencies = [ [[package]] name = "dioxus-web" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "async-trait", "ciborium", @@ -4585,7 +4588,7 @@ dependencies = [ [[package]] name = "dioxus_server_macro" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "axum 0.8.4", "dioxus", @@ -4854,6 +4857,7 @@ dependencies = [ "ed25519", "serde", "sha2", + "signature", "subtle", "zeroize", ] @@ -5822,7 +5826,7 @@ dependencies = [ [[package]] name = "generational-box" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "criterion", "parking_lot", @@ -8126,7 +8130,7 @@ dependencies = [ [[package]] name = "lazy-js-bundle" -version = "0.6.3" +version = "0.7.0-alpha.0" [[package]] name = "lazy_static" @@ -8578,7 +8582,7 @@ dependencies = [ [[package]] name = "manganis" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "const-serialize", "manganis-core", @@ -8587,7 +8591,7 @@ dependencies = [ [[package]] name = "manganis-core" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "const-serialize", "dioxus", @@ -8599,7 +8603,7 @@ dependencies = [ [[package]] name = "manganis-macro" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "dunce", "macro-string", @@ -12168,6 +12172,41 @@ dependencies = [ "to_shmem_derive", ] +[[package]] +name = "self-replace" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03ec815b5eab420ab893f63393878d89c90fdd94c0bcc44c07abb8ad95552fb7" +dependencies = [ + "fastrand", + "tempfile", + "windows-sys 0.52.0", +] + +[[package]] +name = "self_update" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d832c086ece0dacc29fb2947bb4219b8f6e12fe9e40b7108f9e57c4224e47b5c" +dependencies = [ + "either", + "flate2", + "hyper 1.6.0", + "indicatif", + "log", + "quick-xml 0.37.5", + "regex", + "reqwest 0.12.15", + "self-replace", + "semver", + "serde_json", + "tar", + "tempfile", + "urlencoding", + "zip 2.6.1", + "zipsign-api", +] + [[package]] name = "semver" version = "1.0.26" @@ -13414,7 +13453,7 @@ dependencies = [ [[package]] name = "subsecond" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "js-sys", "libc", @@ -13431,7 +13470,7 @@ dependencies = [ [[package]] name = "subsecond-types" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "serde", ] @@ -13463,7 +13502,7 @@ dependencies = [ [[package]] name = "suspense-carousel" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "async-std", "dioxus", @@ -15849,7 +15888,7 @@ dependencies = [ [[package]] name = "wasm-split" -version = "0.1.0" +version = "0.7.0-alpha.0" dependencies = [ "async-once-cell", "wasm-split-macro", @@ -15857,7 +15896,7 @@ dependencies = [ [[package]] name = "wasm-split-cli" -version = "0.1.0" +version = "0.7.0-alpha.0" dependencies = [ "anyhow", "clap", @@ -15891,7 +15930,7 @@ dependencies = [ [[package]] name = "wasm-split-macro" -version = "0.1.0" +version = "0.7.0-alpha.0" dependencies = [ "base16", "digest", @@ -15916,7 +15955,7 @@ dependencies = [ [[package]] name = "wasm-used" -version = "0.6.3" +version = "0.7.0-alpha.0" dependencies = [ "id-arena", "tracing", @@ -17737,6 +17776,7 @@ dependencies = [ "flate2", "indexmap 2.9.0", "memchr", + "time", "zopfli", ] @@ -17751,6 +17791,17 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "zipsign-api" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e7c724c3a8e5833aad6b7028f4f0989fa3a640ce799bf8c352f417b8ef9db3e" +dependencies = [ + "base64 0.22.1", + "ed25519-dalek", + "thiserror 2.0.12", +] + [[package]] name = "zopfli" version = "0.8.2" diff --git a/Cargo.toml b/Cargo.toml index c98029864..2dcc531d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -127,71 +127,71 @@ members = [ ] [workspace.package] -version = "0.6.3" +version = "0.7.0-alpha.0" # dependencies that are shared across packages [workspace.dependencies] -dioxus = { path = "packages/dioxus", version = "0.6.2" } -dioxus-lib = { path = "packages/dioxus-lib", version = "0.6.2" } -dioxus-core = { path = "packages/core", version = "0.6.2" } -dioxus-core-types = { path = "packages/core-types", version = "0.6.2" } -dioxus-core-macro = { path = "packages/core-macro", version = "0.6.2" } -dioxus-config-macro = { path = "packages/config-macro", version = "0.6.2" } -dioxus-router = { path = "packages/router", version = "0.6.2" } -dioxus-router-macro = { path = "packages/router-macro", version = "0.6.2" } -dioxus-document = { path = "packages/document", version = "0.6.2", default-features = false } -dioxus-history = { path = "packages/history", version = "0.6.2", default-features = false } -dioxus-html = { path = "packages/html", version = "0.6.2", default-features = false } -dioxus-html-internal-macro = { path = "packages/html-internal-macro", version = "0.6.2" } -dioxus-hooks = { path = "packages/hooks", version = "0.6.2" } -dioxus-web = { path = "packages/web", version = "0.6.2", default-features = false } -dioxus-isrg = { path = "packages/isrg", version = "0.6.2" } -dioxus-ssr = { path = "packages/ssr", version = "0.6.2", default-features = false } -dioxus-desktop = { path = "packages/desktop", version = "0.6.2", default-features = false } -dioxus-mobile = { path = "packages/mobile", version = "0.6.2" } -dioxus-interpreter-js = { path = "packages/interpreter", version = "0.6.2" } -dioxus-liveview = { path = "packages/liveview", version = "0.6.2" } -dioxus-autofmt = { path = "packages/autofmt", version = "0.6.2" } -dioxus-check = { path = "packages/check", version = "0.6.2" } -dioxus-rsx = { path = "packages/rsx", version = "0.6.2" } -dioxus-rsx-hotreload = { path = "packages/rsx-hotreload", version = "0.6.2" } -dioxus-rsx-rosetta = { path = "packages/rsx-rosetta", version = "0.6.2" } -dioxus-signals = { path = "packages/signals", version = "0.6.2" } -dioxus-cli-config = { path = "packages/cli-config", version = "0.6.2" } -dioxus-cli-opt = { path = "packages/cli-opt", version = "0.6.2" } -dioxus-devtools = { path = "packages/devtools", version = "0.6.2" } -dioxus-devtools-types = { path = "packages/devtools-types", version = "0.6.2" } -dioxus-server = { path = "packages/server", version = "0.6.2" } -dioxus-fullstack = { path = "packages/fullstack", version = "0.6.2" } -dioxus-fullstack-hooks = { path = "packages/fullstack-hooks", version = "0.6.3" } -dioxus-fullstack-protocol = { path = "packages/fullstack-protocol", version = "0.6.3" } -dioxus_server_macro = { path = "packages/server-macro", version = "0.6.2", default-features = false } -dioxus-dx-wire-format = { path = "packages/dx-wire-format", version = "0.6.2" } -dioxus-logger = { path = "packages/logger", version = "0.6.2" } -dioxus-native = { path = "packages/native", version = "0.6.2" } -dioxus-asset-resolver = { path = "packages/asset-resolver", version = "0.6.2" } -dioxus-config-macros = { path = "packages/config-macros", version = "0.6.3" } -const-serialize = { path = "packages/const-serialize", version = "0.6.2" } -const-serialize-macro = { path = "packages/const-serialize-macro", version = "0.6.2" } -generational-box = { path = "packages/generational-box", version = "0.6.2" } -lazy-js-bundle = { path = "packages/lazy-js-bundle", version = "0.6.2" } +dioxus = { path = "packages/dioxus", version = "0.7.0-alpha.0" } +dioxus-lib = { path = "packages/dioxus-lib", version = "0.7.0-alpha.0" } +dioxus-core = { path = "packages/core", version = "0.7.0-alpha.0" } +dioxus-core-types = { path = "packages/core-types", version = "0.7.0-alpha.0" } +dioxus-core-macro = { path = "packages/core-macro", version = "0.7.0-alpha.0" } +dioxus-config-macro = { path = "packages/config-macro", version = "0.7.0-alpha.0" } +dioxus-router = { path = "packages/router", version = "0.7.0-alpha.0" } +dioxus-router-macro = { path = "packages/router-macro", version = "0.7.0-alpha.0" } +dioxus-document = { path = "packages/document", version = "0.7.0-alpha.0", default-features = false } +dioxus-history = { path = "packages/history", version = "0.7.0-alpha.0", default-features = false } +dioxus-html = { path = "packages/html", version = "0.7.0-alpha.0", default-features = false } +dioxus-html-internal-macro = { path = "packages/html-internal-macro", version = "0.7.0-alpha.0" } +dioxus-hooks = { path = "packages/hooks", version = "0.7.0-alpha.0" } +dioxus-web = { path = "packages/web", version = "0.7.0-alpha.0", default-features = false } +dioxus-isrg = { path = "packages/isrg", version = "0.7.0-alpha.0" } +dioxus-ssr = { path = "packages/ssr", version = "0.7.0-alpha.0", default-features = false } +dioxus-desktop = { path = "packages/desktop", version = "0.7.0-alpha.0", default-features = false } +dioxus-mobile = { path = "packages/mobile", version = "0.7.0-alpha.0" } +dioxus-interpreter-js = { path = "packages/interpreter", version = "0.7.0-alpha.0" } +dioxus-liveview = { path = "packages/liveview", version = "0.7.0-alpha.0" } +dioxus-autofmt = { path = "packages/autofmt", version = "0.7.0-alpha.0" } +dioxus-check = { path = "packages/check", version = "0.7.0-alpha.0" } +dioxus-rsx = { path = "packages/rsx", version = "0.7.0-alpha.0" } +dioxus-rsx-hotreload = { path = "packages/rsx-hotreload", version = "0.7.0-alpha.0" } +dioxus-rsx-rosetta = { path = "packages/rsx-rosetta", version = "0.7.0-alpha.0" } +dioxus-signals = { path = "packages/signals", version = "0.7.0-alpha.0" } +dioxus-cli-config = { path = "packages/cli-config", version = "0.7.0-alpha.0" } +dioxus-cli-opt = { path = "packages/cli-opt", version = "0.7.0-alpha.0" } +dioxus-devtools = { path = "packages/devtools", version = "0.7.0-alpha.0" } +dioxus-devtools-types = { path = "packages/devtools-types", version = "0.7.0-alpha.0" } +dioxus-server = { path = "packages/server", version = "0.7.0-alpha.0" } +dioxus-fullstack = { path = "packages/fullstack", version = "0.7.0-alpha.0" } +dioxus-fullstack-hooks = { path = "packages/fullstack-hooks", version = "0.7.0-alpha.0" } +dioxus-fullstack-protocol = { path = "packages/fullstack-protocol", version = "0.7.0-alpha.0" } +dioxus_server_macro = { path = "packages/server-macro", version = "0.7.0-alpha.0", default-features = false } +dioxus-dx-wire-format = { path = "packages/dx-wire-format", version = "0.7.0-alpha.0" } +dioxus-logger = { path = "packages/logger", version = "0.7.0-alpha.0" } +dioxus-native = { path = "packages/native", version = "0.7.0-alpha.0" } +dioxus-asset-resolver = { path = "packages/asset-resolver", version = "0.7.0-alpha.0" } +dioxus-config-macros = { path = "packages/config-macros", version = "0.7.0-alpha.0" } +const-serialize = { path = "packages/const-serialize", version = "0.7.0-alpha.0" } +const-serialize-macro = { path = "packages/const-serialize-macro", version = "0.7.0-alpha.0" } +generational-box = { path = "packages/generational-box", version = "0.7.0-alpha.0" } +lazy-js-bundle = { path = "packages/lazy-js-bundle", version = "0.7.0-alpha.0" } # subsecond -subsecond-types = { path = "packages/subsecond/subsecond-types", version = "0.6.3" } -subsecond = { path = "packages/subsecond/subsecond", version = "0.6.3" } +subsecond-types = { path = "packages/subsecond/subsecond-types", version = "0.7.0-alpha.0" } +subsecond = { path = "packages/subsecond/subsecond", version = "0.7.0-alpha.0" } # manganis -manganis = { path = "packages/manganis/manganis", version = "0.6.2" } -manganis-core = { path = "packages/manganis/manganis-core", version = "0.6.2" } -manganis-macro = { path = "packages/manganis/manganis-macro", version = "0.6.2" } +manganis = { path = "packages/manganis/manganis", version = "0.7.0-alpha.0" } +manganis-core = { path = "packages/manganis/manganis-core", version = "0.7.0-alpha.0" } +manganis-macro = { path = "packages/manganis/manganis-macro", version = "0.7.0-alpha.0" } # wasm-split -wasm-split = { path = "packages/wasm-split/wasm-split", version = "0.1.0" } -wasm-split-macro = { path = "packages/wasm-split/wasm-split-macro", version = "0.1.0" } -wasm-split-cli = { path = "packages/wasm-split/wasm-split-cli", version = "0.1.0" } -wasm-split-harness = { path = "packages/playwright-tests/wasm-split-harness", version = "0.1.0" } +wasm-split = { path = "packages/wasm-split/wasm-split", version = "0.7.0-alpha.0" } +wasm-split-macro = { path = "packages/wasm-split/wasm-split-macro", version = "0.7.0-alpha.0" } +wasm-split-cli = { path = "packages/wasm-split/wasm-split-cli", version = "0.7.0-alpha.0" } +wasm-split-harness = { path = "packages/playwright-tests/wasm-split-harness", version = "0.7.0-alpha.0" } -depinfo = { path = "packages/depinfo", version = "0.6.3" } +depinfo = { path = "packages/depinfo", version = "0.7.0-alpha.0" } warnings = { version = "0.2.1" } # a fork of pretty please for tests - let's get off of this if we can! @@ -400,7 +400,7 @@ documentation = "https://dioxuslabs.com" keywords = ["dom", "ui", "gui", "react", "wasm"] rust-version = "1.80.0" publish = false -version = "0.6.3" +version = "0.7.0-alpha.0" [dependencies] reqwest = { workspace = true, features = ["json"], optional = true } diff --git a/_typos.toml b/_typos.toml index 7f45581e7..60852f0a8 100644 --- a/_typos.toml +++ b/_typos.toml @@ -5,6 +5,9 @@ ratatui = "ratatui" lits = "lits" # https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/seeked_event seeked = "seeked" +# https://developer.apple.com/forums/thread/108953 +# udid = unique device identifier +udid = "udid" [files] extend-exclude = ["translations/*", "CHANGELOG.md", "*.js"] diff --git a/example-projects/ecommerce-site/README.md b/example-projects/ecommerce-site/README.md index 0505b50a6..2515cc8a4 100644 --- a/example-projects/ecommerce-site/README.md +++ b/example-projects/ecommerce-site/README.md @@ -9,7 +9,7 @@ This example app is a fullstack web application leveraging the [FakeStoreAPI](ht 1. Run the following commands to serve the application (see the tailwind example in the main Dioxus repo for more detailed information about setting up tailwind): ```bash -npx tailwindcss -i ./input.css -o ./public/tailwind.css --watch +npx tailwindcss -i ./tailwind.css -o ./public/tailwind.css --watch dx serve ``` diff --git a/example-projects/ecommerce-site/input.css b/example-projects/ecommerce-site/tailwind.css similarity index 100% rename from example-projects/ecommerce-site/input.css rename to example-projects/ecommerce-site/tailwind.css diff --git a/examples/tailwind/input.css b/examples/tailwind/tailwind.css similarity index 100% rename from examples/tailwind/input.css rename to examples/tailwind/tailwind.css diff --git a/lychee.toml b/lychee.toml index 58f7a7852..9e1d00fc6 100644 --- a/lychee.toml +++ b/lychee.toml @@ -3,4 +3,5 @@ exclude = ['file:///', 'https://github.com/DioxusLabs/dioxus/commit'] exclude_path = ['target'] no_progress = false cache = true -max_cache_age = "10d" \ No newline at end of file +max_cache_age = "10d" +accept = ["200..=204", "429"] diff --git a/packages/cli-config/src/lib.rs b/packages/cli-config/src/lib.rs index 7a5d134b0..4eca501d3 100644 --- a/packages/cli-config/src/lib.rs +++ b/packages/cli-config/src/lib.rs @@ -102,15 +102,18 @@ macro_rules! read_env_config { /// For reference, the devserver typically lives on `127.0.0.1:8080` and serves the devserver websocket /// on `127.0.0.1:8080/_dioxus`. pub fn devserver_raw_addr() -> Option { - let ip = std::env::var(DEVSERVER_IP_ENV).ok()?; - let port = std::env::var(DEVSERVER_PORT_ENV).ok()?; + let port = std::env::var(DEVSERVER_PORT_ENV).ok(); if cfg!(target_os = "android") { // Since `adb reverse` is used for Android, the 127.0.0.1 will always be // the correct IP address. + let port = port.unwrap_or("8080".to_string()); return Some(format!("127.0.0.1:{}", port).parse().unwrap()); } + let port = port?; + let ip = std::env::var(DEVSERVER_IP_ENV).ok()?; + format!("{}:{}", ip, port).parse().ok() } diff --git a/packages/cli/Cargo.toml b/packages/cli/Cargo.toml index 9e96f04e1..f17a46bdd 100644 --- a/packages/cli/Cargo.toml +++ b/packages/cli/Cargo.toml @@ -136,6 +136,8 @@ backtrace = "0.3.74" ar = "0.9.0" wasm-bindgen-externref-xform = "0.2.100" pdb = "0.8.0" +self_update = { version = "0.42.0", features = ["archive-tar", "archive-zip", "compression-flate2", "compression-zip-deflate"] } +self-replace = "1.5.0" [build-dependencies] built = { version = "0.7.5", features = ["git2"] } @@ -162,10 +164,7 @@ name = "dx" escargot = "0.5" [package.metadata.binstall] -pkg-url = "{ repo }/releases/download/v{ version }/dx-{ target }-v{ version }{ archive-suffix }" -pkg-fmt = "tgz" - -[package.metadata.binstall.overrides.x86_64-pc-windows-msvc] +pkg-url = "{ repo }/releases/download/v{ version }/dx-{ target }{ archive-suffix }" pkg-fmt = "zip" [package.metadata.docs.rs] diff --git a/packages/cli/assets/android/gen/app/src/main/AndroidManifest.xml.hbs b/packages/cli/assets/android/gen/app/src/main/AndroidManifest.xml.hbs index 811a60623..bd85d856e 100644 --- a/packages/cli/assets/android/gen/app/src/main/AndroidManifest.xml.hbs +++ b/packages/cli/assets/android/gen/app/src/main/AndroidManifest.xml.hbs @@ -1,6 +1,5 @@ - - diff --git a/packages/cli/src/build/builder.rs b/packages/cli/src/build/builder.rs index 95bfc66b5..99eab23c4 100644 --- a/packages/cli/src/build/builder.rs +++ b/packages/cli/src/build/builder.rs @@ -4,7 +4,7 @@ use crate::{ }; use anyhow::Context; use dioxus_cli_opt::process_file_to; -use futures_util::future::OptionFuture; +use futures_util::{future::OptionFuture, pin_mut, FutureExt}; use std::{ env, time::{Duration, Instant, SystemTime}, @@ -617,13 +617,15 @@ impl AppBuilder { _ => vec![], }; + use crate::styles::{GLOW_STYLE, NOTE_STYLE}; + let changed_file = changed_files.first().unwrap(); tracing::info!( - "Hot-patching: {} took {:?}ms", + "Hot-patching: {NOTE_STYLE}{}{NOTE_STYLE:#} took {GLOW_STYLE}{:?}ms{GLOW_STYLE:#}", changed_file - .strip_prefix(std::env::current_dir().unwrap()) - .unwrap_or(changed_file.as_path()) - .display(), + .display() + .to_string() + .trim_start_matches(&self.build.crate_dir().display().to_string()), SystemTime::now() .duration_since(res.time_start) .unwrap() @@ -704,7 +706,7 @@ impl AppBuilder { let target = dioxus_cli_config::android_session_cache_dir().join(bundled_name); tracing::debug!("Pushing asset to device: {target:?}"); - let res = tokio::process::Command::new(&self.build.workspace.android_tools()?.adb) + let res = Command::new(&self.build.workspace.android_tools()?.adb) .arg("push") .arg(changed_file) .arg(&target) @@ -1140,7 +1142,7 @@ We checked the folder: {} let adb = self.build.workspace.android_tools()?.adb.clone(); // Start backgrounded since .open() is called while in the arm of the top-level match - tokio::task::spawn(async move { + let _handle: JoinHandle> = tokio::task::spawn(async move { // call `adb root` so we can push patches to the device if root { if let Err(e) = Command::new(&adb).arg("root").output().await { @@ -1159,54 +1161,79 @@ We checked the folder: {} tracing::error!("failed to forward port {port}: {e}"); } + // Wait for device to be ready + let cmd = Command::new(&adb) + .arg("wait-for-device") + .arg("shell") + .arg(r#"while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done;"#) + .output(); + let cmd_future = cmd.fuse(); + pin_mut!(cmd_future); + tokio::select! { + _ = &mut cmd_future => {} + _ = tokio::time::sleep(Duration::from_millis(50)) => { + tracing::info!("Waiting for android emulator to be ready..."); + _ = cmd_future.await; + } + } + // Install // adb install -r app-debug.apk - if let Err(e) = Command::new(&adb) + let res = Command::new(&adb) .arg("install") .arg("-r") .arg(apk_path) .output() - .await - { - tracing::error!("Failed to install apk with `adb`: {e}"); - }; + .await?; + let std_err = String::from_utf8_lossy(&res.stderr); + if !std_err.is_empty() { + tracing::error!("Failed to install apk with `adb`: {std_err}"); + } + + // Clear the session cache dir on the device + Command::new(&adb) + .arg("shell") + .arg("rm") + .arg("-rf") + .arg(dioxus_cli_config::android_session_cache_dir()) + .output() + .await?; // Write the env vars to a .env file in our session cache let env_file = session_cache.join(".env"); - let contents: String = envs - .iter() - .map(|(key, value)| format!("{key}={value}")) - .collect::>() - .join("\n"); - _ = std::fs::write(&env_file, contents); + _ = std::fs::write( + &env_file, + envs.iter() + .map(|(key, value)| format!("{key}={value}")) + .collect::>() + .join("\n"), + ); // Push the env file to the device - if let Err(e) = tokio::process::Command::new(&adb) + Command::new(&adb) .arg("push") .arg(env_file) .arg(dioxus_cli_config::android_session_cache_dir().join(".env")) .output() - .await - .context("Failed to push asset to device") - { - tracing::error!("Failed to push .env file to device: {e}"); - } + .await?; // eventually, use the user's MainActivity, not our MainActivity // adb shell am start -n dev.dioxus.main/dev.dioxus.main.MainActivity let activity_name = format!("{}/dev.dioxus.main.MainActivity", full_mobile_app_name,); - - if let Err(e) = Command::new(&adb) + let res = Command::new(&adb) .arg("shell") .arg("am") .arg("start") .arg("-n") .arg(activity_name) .output() - .await - { - tracing::error!("Failed to start app with `adb`: {e}"); - }; + .await?; + let std_err = String::from_utf8_lossy(res.stderr.trim_ascii()); + if !std_err.is_empty() { + tracing::error!("Failed to start app with `adb`: {std_err}"); + } + + Ok(()) }); Ok(()) diff --git a/packages/cli/src/build/request.rs b/packages/cli/src/build/request.rs index 07ba4ed7a..d00012820 100644 --- a/packages/cli/src/build/request.rs +++ b/packages/cli/src/build/request.rs @@ -329,7 +329,7 @@ use manganis::{AssetOptions, JsAssetOptions}; use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; use serde::{Deserialize, Serialize}; use std::{ - collections::HashSet, + collections::{BTreeMap, HashSet}, io::Write, path::{Path, PathBuf}, process::Stdio, @@ -370,7 +370,7 @@ pub(crate) struct BuildRequest { pub(crate) platform: Platform, pub(crate) enabled_platforms: Vec, pub(crate) triple: Triple, - pub(crate) _device: bool, + pub(crate) device: bool, pub(crate) package: String, pub(crate) features: Vec, pub(crate) extra_cargo_args: Vec, @@ -536,6 +536,10 @@ impl BuildRequest { // We collect all the platforms it enables first and then select based on the --platform arg let enabled_platforms = Self::enabled_cargo_toml_platforms(main_package, args.no_default_features); + let using_dioxus_explicitly = main_package + .dependencies + .iter() + .any(|dep| dep.name == "dioxus"); let mut features = args.features.clone(); let mut no_default_features = args.no_default_features; @@ -552,6 +556,7 @@ impl BuildRequest { platform } }, + None if !using_dioxus_explicitly => Platform::autodetect_from_cargo_feature("desktop").unwrap(), None => match enabled_platforms.len() { 0 => return Err(anyhow::anyhow!("No platform specified and no platform marked as default in Cargo.toml. Try specifying a platform with `--platform`").into()), 1 => enabled_platforms[0], @@ -565,7 +570,9 @@ impl BuildRequest { }; // Add any features required to turn on the client - features.push(Self::feature_for_platform(main_package, platform)); + if using_dioxus_explicitly { + features.push(Self::feature_for_platform(main_package, platform)); + } // Set the profile of the build if it's not already set // This is mostly used for isolation of builds (preventing thrashing) but also useful to have multiple performance profiles @@ -666,10 +673,10 @@ impl BuildRequest { tracing::debug!( r#"Log Files: -link_args_file: {}, -link_err_file: {}, -rustc_wrapper_args_file: {}, -session_cache_dir: {}"#, + • link_args_file: {}, + • link_err_file: {}, + • rustc_wrapper_args_file: {}, + • session_cache_dir: {}"#, link_args_file.path().display(), link_err_file.path().display(), rustc_wrapper_args_file.path().display(), @@ -684,7 +691,7 @@ session_cache_dir: {}"#, crate_target, profile, triple, - _device: device, + device, workspace, config, enabled_platforms, @@ -886,7 +893,8 @@ session_cache_dir: {}"#, let time_end = SystemTime::now(); let mode = ctx.mode.clone(); let platform = self.platform; - tracing::debug!("Build completed successfully - output location: {:?}", exe); + + tracing::debug!("Build completed successfully: {:?}", exe); Ok(BuildArtifacts { time_end, @@ -905,8 +913,6 @@ session_cache_dir: {}"#, /// This uses "known paths" that have stayed relatively stable during cargo's lifetime. /// One day this system might break and we might need to go back to using the linker approach. fn collect_assets(&self, exe: &Path, ctx: &BuildContext) -> Result { - tracing::debug!("Collecting assets from exe at {} ...", exe.display()); - // walk every file in the incremental cache dir, reading and inserting items into the manifest. let mut manifest = AssetManifest::default(); @@ -1151,7 +1157,7 @@ session_cache_dir: {}"#, // // Many args are passed twice, too, which can be confusing, but generally don't have any real // effect. Note that on macos/ios, there's a special macho header that needs to be set, otherwise - // dyld will complain.a + // dyld will complain. // // Also, some flags in darwin land might become deprecated, need to be super conservative: // - https://developer.apple.com/forums/thread/773907 @@ -1223,7 +1229,6 @@ session_cache_dir: {}"#, // And now we can run the linker with our new args let linker = self.select_linker()?; - let out_exe = self.patch_exe(artifacts.time_start); let out_arg = match self.triple.operating_system { OperatingSystem::Windows => vec![format!("/OUT:{}", out_exe.display())], @@ -1301,6 +1306,13 @@ session_cache_dir: {}"#, // // We don't use *any* of the original linker args since they do lots of custom exports // and other things that we don't need. + // + // The trickiest one here is -Crelocation-model=pic, which forces data symbols + // into a GOT, making it possible to import them from the main module. + // + // I think we can make relocation-model=pic work for non-wasm platforms, enabling + // fully relocatable modules with no host coordination in lieu of sending out + // the aslr slide at runtime. OperatingSystem::Unknown if self.platform == Platform::Web => { out_args.extend([ "--fatal-warnings".to_string(), @@ -1390,7 +1402,6 @@ session_cache_dir: {}"#, "/PDBALTPATH:%_PDB%".to_string(), "/EXPORT:main".to_string(), "/HIGHENTROPYVA:NO".to_string(), - // "/SUBSYSTEM:WINDOWS".to_string(), ]); } @@ -1764,7 +1775,6 @@ session_cache_dir: {}"#, cmd.current_dir(self.workspace_dir()); cmd.env_clear(); cmd.args(rustc_args.args[1..].iter()); - cmd.envs(rustc_args.envs.iter().cloned()); cmd.env_remove("RUSTC_WORKSPACE_WRAPPER"); cmd.env_remove("RUSTC_WRAPPER"); cmd.env_remove(DX_RUSTC_WRAPPER_ENV_VAR); @@ -1775,7 +1785,11 @@ session_cache_dir: {}"#, cmd.arg("-Crelocation-model=pic"); } - tracing::trace!("Direct rustc command: {:#?}", rustc_args.args); + tracing::debug!("Direct rustc: {:#?}", cmd); + + cmd.envs(rustc_args.envs.iter().cloned()); + + tracing::trace!("Setting env vars: {:#?}", rustc_args.envs); Ok(cmd) } @@ -1800,8 +1814,6 @@ session_cache_dir: {}"#, .args(self.cargo_build_arguments(ctx)) .envs(self.cargo_build_env_vars(ctx)?); - tracing::trace!("Cargo command: {:#?}", cmd); - if ctx.mode == BuildMode::Fat { cmd.env( DX_RUSTC_WRAPPER_ENV_VAR, @@ -1816,6 +1828,8 @@ session_cache_dir: {}"#, ); } + tracing::debug!("Cargo: {:#?}", cmd); + Ok(cmd) } } @@ -1942,14 +1956,7 @@ session_cache_dir: {}"#, // // https://github.com/WebAssembly/tool-conventions/blob/main/DynamicLinking.md // - // The trickiest one here is -Crelocation-model=pic, which forces data symbols - // into a GOT, making it possible to import them from the main module. - // - // I think we can make relocation-model=pic work for non-wasm platforms, enabling - // fully relocatable modules with no host coordination in lieu of sending out - // the aslr slide at runtime. - // - // The other tricky one is -Ctarget-cpu=mvp, which prevents rustc from generating externref + // The tricky one is -Ctarget-cpu=mvp, which prevents rustc from generating externref // entries. // // https://blog.rust-lang.org/2024/09/24/webassembly-targets-change-in-default-target-features/#disabling-on-by-default-webassembly-proposals @@ -1958,7 +1965,6 @@ session_cache_dir: {}"#, if self.platform == Platform::Web || self.triple.operating_system == OperatingSystem::Wasi { - // cargo_args.push("-Crelocation-model=pic".into()); cargo_args.push("-Ctarget-cpu=mvp".into()); cargo_args.push("-Clink-arg=--no-gc-sections".into()); cargo_args.push("-Clink-arg=--growable-table".into()); @@ -2324,12 +2330,19 @@ session_cache_dir: {}"#, app.join("proguard-rules.pro"), include_bytes!("../../assets/android/gen/app/proguard-rules.pro"), )?; - write( - app.join("src").join("main").join("AndroidManifest.xml"), - hbs.render_template( + + let manifest_xml = match self.config.application.android_manifest.as_deref() { + Some(manifest) => std::fs::read_to_string(self.package_manifest_dir().join(manifest)) + .context("Failed to locate custom AndroidManifest.xml")?, + _ => hbs.render_template( include_str!("../../assets/android/gen/app/src/main/AndroidManifest.xml.hbs"), &hbs_data, )?, + }; + + write( + app.join("src").join("main").join("AndroidManifest.xml"), + manifest_xml, )?; // Write the main activity manually since tao dropped support for it @@ -2657,8 +2670,6 @@ session_cache_dir: {}"#, return platforms; }; - tracing::debug!("Default features: {default:?}"); - // we only trace features 1 level deep.. for feature in default.iter() { // If the user directly specified a platform we can just use that. @@ -2688,8 +2699,6 @@ session_cache_dir: {}"#, platforms.sort(); platforms.dedup(); - tracing::debug!("Default platforms: {platforms:?}"); - platforms } @@ -2876,13 +2885,15 @@ session_cache_dir: {}"#, // If pre-compressing is enabled, we can pre_compress the wasm-bindgen output let pre_compress = self.should_pre_compress_web_assets(self.release); - ctx.status_compressing_assets(); - let asset_dir = self.asset_dir(); - tokio::task::spawn_blocking(move || { - crate::fastfs::pre_compress_folder(&asset_dir, pre_compress) - }) - .await - .unwrap()?; + if pre_compress { + ctx.status_compressing_assets(); + let asset_dir = self.asset_dir(); + tokio::task::spawn_blocking(move || { + crate::fastfs::pre_compress_folder(&asset_dir, pre_compress) + }) + .await + .unwrap()?; + } } Platform::MacOS => {} Platform::Windows => {} @@ -3132,6 +3143,22 @@ session_cache_dir: {}"#, pub executable_name: String, } + // Attempt to use the user's manually specified + let _app = &self.config.application; + match platform { + Platform::MacOS => { + if let Some(macos_info_plist) = _app.macos_info_plist.as_deref() { + return Ok(std::fs::read_to_string(macos_info_plist)?); + } + } + Platform::Ios => { + if let Some(macos_info_plist) = _app.ios_info_plist.as_deref() { + return Ok(std::fs::read_to_string(macos_info_plist)?); + } + } + _ => {} + } + match platform { Platform::MacOS => handlebars::Handlebars::new() .render_template( @@ -3273,9 +3300,15 @@ session_cache_dir: {}"#, create_dir_all(self.exe_dir())?; create_dir_all(self.asset_dir())?; - tracing::debug!("Initialized Root dir: {:?}", self.root_dir()); - tracing::debug!("Initialized Exe dir: {:?}", self.exe_dir()); - tracing::debug!("Initialized Asset dir: {:?}", self.asset_dir()); + tracing::debug!( + r#"Initialized build dirs: + • root dir: {:?} + • exe dir: {:?} + • asset dir: {:?}"#, + self.root_dir(), + self.exe_dir(), + self.asset_dir(), + ); // we could download the templates from somewhere (github?) but after having banged my head against // cargo-mobile2 for ages, I give up with that. We're literally just going to hardcode the templates @@ -3387,7 +3420,6 @@ session_cache_dir: {}"#, /// This should generally be only called on the first build since it takes time to verify the tooling /// is in place, and we don't want to slow down subsequent builds. pub(crate) async fn verify_tooling(&self, ctx: &BuildContext) -> Result<()> { - tracing::debug!("Verifying tooling..."); ctx.status_installing_tooling(); self @@ -3768,4 +3800,116 @@ r#" + + + +
+
+
+
+
+
+
+ + + + + +

Your app is being rebuilt.

+
+

A non-hot-reloadable change occurred and we must rebuild.

+
+
+
+
+ + + diff --git a/packages/desktop/src/index.html b/packages/desktop/src/assets/prod.index.html similarity index 100% rename from packages/desktop/src/index.html rename to packages/desktop/src/assets/prod.index.html diff --git a/packages/desktop/src/launch.rs b/packages/desktop/src/launch.rs index d159dac8f..027f63f04 100644 --- a/packages/desktop/src/launch.rs +++ b/packages/desktop/src/launch.rs @@ -8,6 +8,52 @@ use dioxus_document::eval; use std::any::Any; use tao::event::{Event, StartCause, WindowEvent}; +/// Launches the WebView and runs the event loop +pub fn launch(root: fn() -> Element) { + launch_cfg(root, vec![], vec![]); +} + +/// Launches the WebView and runs the event loop, with configuration and root props. +pub fn launch_cfg( + root: fn() -> Element, + contexts: Vec Box + Send + Sync>>, + platform_config: Vec>, +) { + let mut virtual_dom = VirtualDom::new(root); + + for context in contexts { + virtual_dom.insert_any_root_context(context()); + } + + let platform_config = *platform_config + .into_iter() + .find_map(|cfg| cfg.downcast::().ok()) + .unwrap_or_default(); + + launch_virtual_dom(virtual_dom, platform_config) +} + +/// Launches the WebView and runs the event loop, with configuration and root props. +pub fn launch_virtual_dom(virtual_dom: VirtualDom, desktop_config: Config) -> ! { + #[cfg(feature = "tokio_runtime")] + { + tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .unwrap() + .block_on(tokio::task::unconstrained(async move { + launch_virtual_dom_blocking(virtual_dom, desktop_config) + })); + + unreachable!("The desktop launch function will never exit") + } + + #[cfg(not(feature = "tokio_runtime"))] + { + launch_virtual_dom_blocking(virtual_dom, desktop_config); + } +} + /// Launch the WebView and run the event loop, with configuration and root props. /// /// This will block the main thread, and *must* be spawned on the main thread. This function does not assume any runtime @@ -111,43 +157,68 @@ pub fn launch_virtual_dom_blocking(virtual_dom: VirtualDom, mut desktop_config: }) } -/// Launches the WebView and runs the event loop, with configuration and root props. -pub fn launch_virtual_dom(virtual_dom: VirtualDom, desktop_config: Config) -> ! { - #[cfg(feature = "tokio_runtime")] - { - tokio::runtime::Builder::new_multi_thread() - .enable_all() - .build() - .unwrap() - .block_on(tokio::task::unconstrained(async move { - launch_virtual_dom_blocking(virtual_dom, desktop_config) - })); - - unreachable!("The desktop launch function will never exit") - } - - #[cfg(not(feature = "tokio_runtime"))] - { - launch_virtual_dom_blocking(virtual_dom, desktop_config); - } +/// Expose the `Java_dev_dioxus_main_WryActivity_create` function to the JNI layer. +/// We hardcode these to have a single trampoline for host Java code to call into. +/// +/// This saves us from having to plumb the top-level package name all the way down into +/// this file. This is better for modularity (ie just call dioxus' main to run the app) as +/// well as cache thrashing since this crate doesn't rely on external env vars. +/// +/// The CLI is expecting to find `dev.dioxus.main` in the final library. If you find a need to +/// change this, you'll need to change the CLI as well. +#[cfg(target_os = "android")] +#[no_mangle] +#[inline(never)] +pub extern "C" fn start_app() { + wry::android_binding!(dev_dioxus, main, wry); + tao::android_binding!( + dev_dioxus, + main, + WryActivity, + wry::android_setup, + dioxus_main_root_fn, + tao + ); } -/// Launches the WebView and runs the event loop, with configuration and root props. -pub fn launch( - root: fn() -> Element, - contexts: Vec Box + Send + Sync>>, - platform_config: Vec>, -) -> ! { - let mut virtual_dom = VirtualDom::new(root); +#[cfg(target_os = "android")] +#[doc(hidden)] +pub fn dioxus_main_root_fn() { + // we're going to find the `main` symbol using dlsym directly and call it + unsafe { + let mut main_fn_ptr = libc::dlsym(libc::RTLD_DEFAULT, b"main\0".as_ptr() as _); - for context in contexts { - virtual_dom.insert_any_root_context(context()); - } + if main_fn_ptr.is_null() { + main_fn_ptr = libc::dlsym(libc::RTLD_DEFAULT, b"_main\0".as_ptr() as _); + } - let platform_config = *platform_config - .into_iter() - .find_map(|cfg| cfg.downcast::().ok()) - .unwrap_or_default(); + if main_fn_ptr.is_null() { + panic!("Failed to find main symbol"); + } - launch_virtual_dom(virtual_dom, platform_config) + // Set the env vars that rust code might expect, passed off to us by the android app + // Doing this before main emulates the behavior of a regular executable + if cfg!(target_os = "android") && cfg!(debug_assertions) { + load_env_file_from_session_cache(); + } + + let main_fn: extern "C" fn() = std::mem::transmute(main_fn_ptr); + main_fn(); + }; +} + +/// Load the env file from the session cache if we're in debug mode and on android +/// +/// This is a slightly hacky way of being able to use std::env::var code in android apps without +/// going through their custom java-based system. +#[cfg(target_os = "android")] +fn load_env_file_from_session_cache() { + let env_file = dioxus_cli_config::android_session_cache_dir().join(".env"); + if let Some(env_file) = std::fs::read_to_string(&env_file).ok() { + for line in env_file.lines() { + if let Some((key, value)) = line.trim().split_once('=') { + std::env::set_var(key, value); + } + } + } } diff --git a/packages/desktop/src/protocol.rs b/packages/desktop/src/protocol.rs index 27c2a76c6..b694bc1e6 100644 --- a/packages/desktop/src/protocol.rs +++ b/packages/desktop/src/protocol.rs @@ -19,7 +19,11 @@ const EVENTS_PATH: &str = "http://dioxus.index.html/__events"; #[cfg(not(any(target_os = "android", target_os = "windows")))] const EVENTS_PATH: &str = "dioxus://index.html/__events"; -static DEFAULT_INDEX: &str = include_str!("./index.html"); +#[cfg(debug_assertions)] +static DEFAULT_INDEX: &str = include_str!("./assets/dev.index.html"); + +#[cfg(not(debug_assertions))] +static DEFAULT_INDEX: &str = include_str!("./assets/prod.index.html"); #[allow(clippy::too_many_arguments)] // just for now, should fix this eventually /// Handle a request from the webview diff --git a/packages/desktop/src/webview.rs b/packages/desktop/src/webview.rs index b9d8ecad1..67d0fb18c 100644 --- a/packages/desktop/src/webview.rs +++ b/packages/desktop/src/webview.rs @@ -19,8 +19,8 @@ use dioxus_history::{History, MemoryHistory}; use dioxus_hooks::to_owned; use dioxus_html::{HasFileData, HtmlEvent, PlatformEventData}; use futures_util::{pin_mut, FutureExt}; -use std::cell::OnceCell; use std::sync::Arc; +use std::{cell::OnceCell, time::Duration}; use std::{rc::Rc, task::Waker}; use wry::{DragDropEvent, RequestAsyncResponder, WebContext, WebViewBuilder}; @@ -480,6 +480,31 @@ impl WebviewInstance { .webview .evaluate_script("window.interpreter.kickAllStylesheetsOnPage()"); } + + /// Displays a toast to the developer. + pub(crate) fn show_toast( + &self, + header_text: &str, + message: &str, + level: &str, + duration: Duration, + after_reload: bool, + ) { + let as_ms = duration.as_millis(); + + let js_fn_name = match after_reload { + true => "scheduleDXToast", + false => "showDXToast", + }; + + _ = self.desktop_context.webview.evaluate_script(&format!( + r#" + if (typeof {js_fn_name} !== "undefined") {{ + window.{js_fn_name}("{header_text}", "{message}", "{level}", {as_ms}); + }} + "#, + )); + } } /// A synchronous response to a browser event which may prevent the default browser's action diff --git a/packages/devtools/src/lib.rs b/packages/devtools/src/lib.rs index 65394a6a1..077ed6c58 100644 --- a/packages/devtools/src/lib.rs +++ b/packages/devtools/src/lib.rs @@ -50,7 +50,33 @@ pub fn try_apply_changes(dom: &VirtualDom, msg: &HotReloadMsg) -> Result<(), Pat /// /// This doesn't use any form of security or protocol, so it's not safe to expose to the internet. #[cfg(not(target_arch = "wasm32"))] -pub fn connect(endpoint: String, mut callback: impl FnMut(DevserverMsg) + Send + 'static) { +pub fn connect(callback: impl FnMut(DevserverMsg) + Send + 'static) { + let Some(endpoint) = dioxus_cli_config::devserver_ws_endpoint() else { + return; + }; + + connect_at(endpoint, callback); +} + +/// Connect to the devserver and handle hot-patch messages only, implementing the subsecond hotpatch +/// protocol. +/// +/// This is intended to be used by non-dioxus projects that want to use hotpatching. +/// +/// To handle the full devserver protocol, use `connect` instead. +#[cfg(not(target_arch = "wasm32"))] +pub fn connect_subsecond() { + connect(|msg| { + if let DevserverMsg::HotReload(hot_reload_msg) = msg { + if let Some(jumptable) = hot_reload_msg.jump_table { + unsafe { subsecond::apply_patch(jumptable).unwrap() }; + } + } + }); +} + +#[cfg(not(target_arch = "wasm32"))] +pub fn connect_at(endpoint: String, mut callback: impl FnMut(DevserverMsg) + Send + 'static) { std::thread::spawn(move || { let uri = format!( "{endpoint}?aslr_reference={}&build_id={}", diff --git a/packages/dioxus/Cargo.toml b/packages/dioxus/Cargo.toml index daa260150..2204a5e21 100644 --- a/packages/dioxus/Cargo.toml +++ b/packages/dioxus/Cargo.toml @@ -80,7 +80,7 @@ router = ["dep:dioxus-router"] # Platforms fullstack = ["dep:dioxus-fullstack", "dioxus-config-macro/fullstack", "dep:serde"] desktop = ["dep:dioxus-desktop", "dioxus-fullstack?/desktop", "dioxus-config-macro/desktop"] -mobile = ["dep:dioxus-mobile", "dioxus-fullstack?/mobile", "dioxus-config-macro/mobile"] +mobile = ["dep:dioxus-mobile", "dep:dioxus-desktop", "dioxus-fullstack?/mobile", "dioxus-config-macro/mobile"] web = [ "dep:dioxus-web", "dioxus-fullstack?/web", diff --git a/packages/dioxus/src/launch.rs b/packages/dioxus/src/launch.rs index cb9b8c08d..4bc60e4b6 100644 --- a/packages/dioxus/src/launch.rs +++ b/packages/dioxus/src/launch.rs @@ -332,12 +332,12 @@ impl LaunchBuilder { #[cfg(feature = "mobile")] if matches!(platform, KnownPlatform::Mobile) { - return dioxus_mobile::launch_bindings::launch(app, contexts, configs); + return dioxus_desktop::launch::launch_cfg(app, contexts, configs); } #[cfg(feature = "desktop")] if matches!(platform, KnownPlatform::Desktop) { - return dioxus_desktop::launch::launch(app, contexts, configs); + return dioxus_desktop::launch::launch_cfg(app, contexts, configs); } #[cfg(feature = "server")] diff --git a/packages/liveview/src/pool.rs b/packages/liveview/src/pool.rs index add0910b1..0c1715fb6 100644 --- a/packages/liveview/src/pool.rs +++ b/packages/liveview/src/pool.rs @@ -119,9 +119,7 @@ pub async fn run(mut vdom: VirtualDom, ws: impl LiveViewSocket) -> Result<(), Li #[cfg(all(feature = "devtools", debug_assertions))] let mut hot_reload_rx = { let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); - if let Some(endpoint) = dioxus_cli_config::devserver_ws_endpoint() { - dioxus_devtools::connect(endpoint, move |template| _ = tx.send(template)); - } + dioxus_devtools::connect(move |template| _ = tx.send(template)); rx }; diff --git a/packages/mobile/src/lib.rs b/packages/mobile/src/lib.rs index 88d8e5051..07c920018 100644 --- a/packages/mobile/src/lib.rs +++ b/packages/mobile/src/lib.rs @@ -5,23 +5,6 @@ pub use dioxus_desktop::*; use dioxus_lib::prelude::*; use std::any::Any; -use std::sync::Mutex; - -pub mod launch_bindings { - - use super::*; - pub fn launch( - root: fn() -> Element, - contexts: Vec Box + Send + Sync>>, - platform_config: Vec>, - ) { - super::launch_cfg(root, contexts, platform_config); - } - - pub fn launch_virtual_dom(_virtual_dom: VirtualDom, _desktop_config: Config) -> ! { - todo!() - } -} /// Launch via the binding API pub fn launch(root: fn() -> Element) { @@ -33,126 +16,5 @@ pub fn launch_cfg( contexts: Vec Box + Send + Sync>>, platform_config: Vec>, ) { - #[cfg(target_os = "android")] - { - *APP_OBJECTS.lock().unwrap() = Some(BoundLaunchObjects { - root, - contexts, - platform_config, - }); - } - - #[cfg(not(target_os = "android"))] - { - dioxus_desktop::launch::launch(root, contexts, platform_config); - } -} - -/// We need to store the root function and contexts in a static so that when the tao bindings call -/// "start_app", that the original function arguments are still around. -/// -/// If you look closely, you'll notice that we impl Send for this struct. This would normally be -/// unsound. However, we know that the thread that created these objects ("main()" - see JNI_OnLoad) -/// is finished once `start_app` is called. This is similar to how an Rc is technically safe -/// to move between threads if you can prove that no other thread is using the Rc at the same time. -/// Crates like https://crates.io/crates/sendable exist that build on this idea but with runtimk, -/// validation that the current thread is the one that created the object. -/// -/// Since `main()` completes, the only reader of this data will be `start_app`, so it's okay to -/// impl this as Send/Sync. -/// -/// Todo(jon): the visibility of functions in this module is too public. Make sure to hide them before -/// releasing 0.7. -struct BoundLaunchObjects { - root: fn() -> Element, - contexts: Vec Box + Send + Sync>>, - platform_config: Vec>, -} - -unsafe impl Send for BoundLaunchObjects {} -unsafe impl Sync for BoundLaunchObjects {} - -static APP_OBJECTS: Mutex> = Mutex::new(None); - -#[doc(hidden)] -pub fn root() { - let app = APP_OBJECTS - .lock() - .expect("APP_FN_PTR lock failed") - .take() - .expect("Android to have set the app trampoline"); - - let BoundLaunchObjects { - root, - contexts, - platform_config, - } = app; - - dioxus_desktop::launch::launch(root, contexts, platform_config); -} - -/// Expose the `Java_dev_dioxus_main_WryActivity_create` function to the JNI layer. -/// We hardcode these to have a single trampoline for host Java code to call into. -/// -/// This saves us from having to plumb the top-level package name all the way down into -/// this file. This is better for modularity (ie just call dioxus' main to run the app) as -/// well as cache thrashing since this crate doesn't rely on external env vars. -/// -/// The CLI is expecting to find `dev.dioxus.main` in the final library. If you find a need to -/// change this, you'll need to change the CLI as well. -#[cfg(target_os = "android")] -#[no_mangle] -#[inline(never)] -pub extern "C" fn start_app() { - tao::android_binding!(dev_dioxus, main, WryActivity, wry::android_setup, root, tao); - wry::android_binding!(dev_dioxus, main, wry); -} - -/// Call our `main` function to initialize the rust runtime and set the launch binding trampoline -#[cfg(target_os = "android")] -#[no_mangle] -#[inline(never)] -pub extern "C" fn JNI_OnLoad( - _vm: *mut libc::c_void, - _reserved: *mut libc::c_void, -) -> jni::sys::jint { - // we're going to find the `main` symbol using dlsym directly and call it - unsafe { - let mut main_fn_ptr = libc::dlsym(libc::RTLD_DEFAULT, b"main\0".as_ptr() as _); - - if main_fn_ptr.is_null() { - main_fn_ptr = libc::dlsym(libc::RTLD_DEFAULT, b"_main\0".as_ptr() as _); - } - - if main_fn_ptr.is_null() { - panic!("Failed to find main symbol"); - } - - // Set the env vars that rust code might expect, passed off to us by the android app - // Doing this before main emulates the behavior of a regular executable - if cfg!(target_os = "android") && cfg!(debug_assertions) { - load_env_file_from_session_cache(); - } - - let main_fn: extern "C" fn() = std::mem::transmute(main_fn_ptr); - main_fn(); - }; - - jni::sys::JNI_VERSION_1_6 -} - -/// Load the env file from the session cache if we're in debug mode and on android -/// -/// This is a slightly hacky way of being able to use std::env::var code in android apps without -/// going through their custom java-based system. -#[cfg(target_os = "android")] -fn load_env_file_from_session_cache() { - let env_file = dioxus_cli_config::android_session_cache_dir().join(".env"); - if let Some(env_file) = std::fs::read_to_string(&env_file).ok() { - for line in env_file.lines() { - if let Some((key, value)) = line.trim().split_once('=') { - std::env::set_var(key, value); - } - } - } + dioxus_desktop::launch::launch_cfg(root, contexts, platform_config); } diff --git a/packages/native/src/lib.rs b/packages/native/src/lib.rs index 833f5037a..c3f5df9fa 100644 --- a/packages/native/src/lib.rs +++ b/packages/native/src/lib.rs @@ -69,13 +69,11 @@ pub fn launch_cfg_with_props( ))] { use crate::event::DioxusNativeEvent; - if let Some(endpoint) = dioxus_cli_config::devserver_ws_endpoint() { - let proxy = event_loop.create_proxy(); - dioxus_devtools::connect(endpoint, move |event| { - let dxn_event = DioxusNativeEvent::DevserverEvent(event); - let _ = proxy.send_event(BlitzShellEvent::embedder_event(dxn_event)); - }) - } + let proxy = event_loop.create_proxy(); + dioxus_devtools::connect(move |event| { + let dxn_event = DioxusNativeEvent::DevserverEvent(event); + let _ = proxy.send_event(BlitzShellEvent::embedder_event(dxn_event)); + }) } // Spin up the virtualdom diff --git a/packages/server/src/launch.rs b/packages/server/src/launch.rs index 1c2d21a30..3b094ebdc 100644 --- a/packages/server/src/launch.rs +++ b/packages/server/src/launch.rs @@ -51,11 +51,7 @@ async fn serve_server( ) { let (devtools_tx, mut devtools_rx) = futures_channel::mpsc::unbounded(); - if let Some(endpoint) = dioxus_cli_config::devserver_ws_endpoint() { - dioxus_devtools::connect(endpoint, move |msg| { - _ = devtools_tx.unbounded_send(msg); - }) - } + dioxus_devtools::connect(move |msg| _ = devtools_tx.unbounded_send(msg)); let platform_config = platform_config .into_iter() diff --git a/packages/subsecond/subsecond/src/lib.rs b/packages/subsecond/subsecond/src/lib.rs index 63d657d11..325ccce5f 100644 --- a/packages/subsecond/subsecond/src/lib.rs +++ b/packages/subsecond/subsecond/src/lib.rs @@ -756,8 +756,6 @@ macro_rules! impl_hot_function { unsafe fn call_as_ptr(&mut self, args: ($($arg,)*)) -> Self::Return { unsafe { if let Some(jump_table) = get_jump_table() { - - let real = std::mem::transmute_copy::(&self) as *const (); // Android implements MTE / pointer tagging and we need to preserve the tag. @@ -765,7 +763,7 @@ macro_rules! impl_hot_function { // This is only implemented on 64-bit platforms since pointer tagging is not available on 32-bit platforms // In dev, Dioxus disables MTE to work around this issue, but we still handle it anyways. #[cfg(all(target_pointer_width = "64", target_os = "android"))] let nibble = real as u64 & 0xFF00_0000_0000_0000; - #[cfg(target_pointer_width = "64")] let real = real as u64 & 0x00FFF_FFF_FFFF_FFFF; + #[cfg(all(target_pointer_width = "64", target_os = "android"))] let real = real as u64 & 0x00FFF_FFF_FFFF_FFFF; #[cfg(target_pointer_width = "64")] let real = real as u64; diff --git a/packages/wasm-split/wasm-split-cli/Cargo.toml b/packages/wasm-split/wasm-split-cli/Cargo.toml index 68404e00c..e06e705f1 100644 --- a/packages/wasm-split/wasm-split-cli/Cargo.toml +++ b/packages/wasm-split/wasm-split-cli/Cargo.toml @@ -1,7 +1,14 @@ [package] name = "wasm-split-cli" -version = "0.1.0" edition = "2021" +version = { workspace = true } +authors = ["Jonathan Kelley"] +description = "CLI-support for wasm-split - a tool for splitting up large WASM binaries into smaller chunks" +repository = "https://github.com/DioxusLabs/dioxus/" +license = "MIT OR Apache-2.0" +keywords = ["wasm", "cli", "split", "dioxus"] +rust-version = "1.81.0" + [dependencies] anyhow = { workspace = true } diff --git a/packages/wasm-split/wasm-split-macro/Cargo.toml b/packages/wasm-split/wasm-split-macro/Cargo.toml index 1d00c09b5..b5e0d307d 100644 --- a/packages/wasm-split/wasm-split-macro/Cargo.toml +++ b/packages/wasm-split/wasm-split-macro/Cargo.toml @@ -1,7 +1,14 @@ [package] name = "wasm-split-macro" -version = "0.1.0" edition = "2021" +version = { workspace = true } +authors = ["Jonathan Kelley"] +description = "macro crate for wasm-split - a tool for splitting up large WASM binaries into smaller chunks" +repository = "https://github.com/DioxusLabs/dioxus/" +license = "MIT OR Apache-2.0" +keywords = ["wasm", "cli", "split", "dioxus"] +rust-version = "1.81.0" + [dependencies] syn = { workspace = true, features = ["full"] } diff --git a/packages/wasm-split/wasm-split/Cargo.toml b/packages/wasm-split/wasm-split/Cargo.toml index 59b262ede..61dedb53c 100644 --- a/packages/wasm-split/wasm-split/Cargo.toml +++ b/packages/wasm-split/wasm-split/Cargo.toml @@ -1,7 +1,14 @@ [package] name = "wasm-split" -version = "0.1.0" +version = { workspace = true } edition = "2021" +authors = ["Jonathan Kelley"] +description = "A tool for splitting up large WASM binaries into smaller chunks" +repository = "https://github.com/DioxusLabs/dioxus/" +license = "MIT OR Apache-2.0" +keywords = ["wasm", "cli", "split", "dioxus"] +rust-version = "1.81.0" + [dependencies] async-once-cell = { workspace = true, features = ["std"] }