CLI self-updater, warn on version mismatch, direct install.sh option, androidmanifest and info.plist customization, bump to 0.7-alpha.0 (#4095)
* wip.... bun installer * - warn on incompatible versions - clean up some logs - add coloring to log levels * add toasts to desktop/mobile * Auto open simulators * auto boot android * preserve url * pull out some of the warnings * add self-updater * wip: mcp * add install.sh and adjust binstall path * add some cuter styling to logs! * update "input.css" * update other input.css * style a bit more * change getting started * add windows installer * move dioxus-mobile into dioxus-desktop add sentry wip to cli * shorten timeout of toast * fix cli display * wire up customization of android manifest * udid is a real word * add 429 to lychee cache * accept all 200-204 and 429
This commit is contained in:
1 parent
53ef78823d
commit
4d3d55a7a3
56 files changed
+1560
-548
No files matched your search
@@ -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"
|
||||||
Executable
+104
@@ -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
|
||||||
@@ -98,7 +98,7 @@ jobs:
|
|||||||
bin: dx
|
bin: dx
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
target: ${{ matrix.platform.target }}
|
target: ${{ matrix.platform.target }}
|
||||||
archive: $bin-$target-${{ env.RELEASE_TAG }}
|
archive: $bin-$target
|
||||||
checksum: sha256
|
checksum: sha256
|
||||||
manifest_path: packages/cli/Cargo.toml
|
manifest_path: packages/cli/Cargo.toml
|
||||||
ref: refs/tags/${{ env.RELEASE_POST }}
|
ref: refs/tags/${{ env.RELEASE_POST }}
|
||||||
|
|||||||
Generated
+109
-58
@@ -2624,7 +2624,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "const-serialize"
|
name = "const-serialize"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"const-serialize",
|
"const-serialize",
|
||||||
"const-serialize-macro",
|
"const-serialize-macro",
|
||||||
@@ -2634,7 +2634,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "const-serialize-macro"
|
name = "const-serialize-macro"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -3398,7 +3398,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "depinfo"
|
name = "depinfo"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
]
|
]
|
||||||
@@ -3569,7 +3569,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus"
|
name = "dioxus"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"criterion",
|
"criterion",
|
||||||
"dioxus",
|
"dioxus",
|
||||||
@@ -3610,7 +3610,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-asset-resolver"
|
name = "dioxus-asset-resolver"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dioxus-cli-config",
|
"dioxus-cli-config",
|
||||||
"http 1.3.1",
|
"http 1.3.1",
|
||||||
@@ -3625,7 +3625,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-autofmt"
|
name = "dioxus-autofmt"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dioxus-rsx",
|
"dioxus-rsx",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
@@ -3638,7 +3638,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-check"
|
name = "dioxus-check"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indoc",
|
"indoc",
|
||||||
"owo-colors",
|
"owo-colors",
|
||||||
@@ -3650,7 +3650,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-cli"
|
name = "dioxus-cli"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi-to-html",
|
"ansi-to-html",
|
||||||
"ansi-to-tui",
|
"ansi-to-tui",
|
||||||
@@ -3725,6 +3725,8 @@ dependencies = [
|
|||||||
"regex",
|
"regex",
|
||||||
"reqwest 0.12.15",
|
"reqwest 0.12.15",
|
||||||
"rustls 0.23.27",
|
"rustls 0.23.27",
|
||||||
|
"self-replace",
|
||||||
|
"self_update",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"shell-words",
|
"shell-words",
|
||||||
@@ -3762,14 +3764,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-cli-config"
|
name = "dioxus-cli-config"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-cli-opt"
|
name = "dioxus-cli-opt"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"browserslist-rs 0.16.0",
|
"browserslist-rs 0.16.0",
|
||||||
@@ -3828,7 +3830,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-config-macro"
|
name = "dioxus-config-macro"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -3836,11 +3838,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-config-macros"
|
name = "dioxus-config-macros"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-core"
|
name = "dioxus-core"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"const_format",
|
"const_format",
|
||||||
"dioxus",
|
"dioxus",
|
||||||
@@ -3871,7 +3873,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-core-macro"
|
name = "dioxus-core-macro"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"convert_case 0.8.0",
|
"convert_case 0.8.0",
|
||||||
"dioxus",
|
"dioxus",
|
||||||
@@ -3887,14 +3889,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-core-types"
|
name = "dioxus-core-types"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-desktop"
|
name = "dioxus-desktop"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
@@ -3922,6 +3924,7 @@ dependencies = [
|
|||||||
"infer",
|
"infer",
|
||||||
"jni",
|
"jni",
|
||||||
"lazy-js-bundle",
|
"lazy-js-bundle",
|
||||||
|
"libc",
|
||||||
"muda 0.16.1",
|
"muda 0.16.1",
|
||||||
"ndk",
|
"ndk",
|
||||||
"ndk-context",
|
"ndk-context",
|
||||||
@@ -3951,7 +3954,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-devtools"
|
name = "dioxus-devtools"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dioxus-cli-config",
|
"dioxus-cli-config",
|
||||||
"dioxus-core",
|
"dioxus-core",
|
||||||
@@ -3969,7 +3972,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-devtools-types"
|
name = "dioxus-devtools-types"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dioxus-core",
|
"dioxus-core",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -3978,7 +3981,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-document"
|
name = "dioxus-document"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dioxus",
|
"dioxus",
|
||||||
"dioxus-core",
|
"dioxus-core",
|
||||||
@@ -3996,7 +3999,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-dx-wire-format"
|
name = "dioxus-dx-wire-format"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cargo_metadata",
|
"cargo_metadata",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -4005,7 +4008,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-examples"
|
name = "dioxus-examples"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-std",
|
"async-std",
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
@@ -4031,7 +4034,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-ext"
|
name = "dioxus-ext"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dioxus-autofmt",
|
"dioxus-autofmt",
|
||||||
"dioxus-rsx-rosetta",
|
"dioxus-rsx-rosetta",
|
||||||
@@ -4042,7 +4045,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-fullstack"
|
name = "dioxus-fullstack"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"aws-lc-rs",
|
"aws-lc-rs",
|
||||||
@@ -4088,7 +4091,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-fullstack-hooks"
|
name = "dioxus-fullstack-hooks"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dioxus",
|
"dioxus",
|
||||||
"dioxus-core",
|
"dioxus-core",
|
||||||
@@ -4103,7 +4106,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-fullstack-protocol"
|
name = "dioxus-fullstack-protocol"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"ciborium",
|
"ciborium",
|
||||||
@@ -4114,7 +4117,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-history"
|
name = "dioxus-history"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dioxus",
|
"dioxus",
|
||||||
"dioxus-core",
|
"dioxus-core",
|
||||||
@@ -4123,7 +4126,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-hooks"
|
name = "dioxus-hooks"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dioxus",
|
"dioxus",
|
||||||
"dioxus-core",
|
"dioxus-core",
|
||||||
@@ -4142,7 +4145,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-html"
|
name = "dioxus-html"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"dioxus",
|
"dioxus",
|
||||||
@@ -4171,7 +4174,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-html-internal-macro"
|
name = "dioxus-html-internal-macro"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"convert_case 0.8.0",
|
"convert_case 0.8.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
@@ -4182,7 +4185,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-interpreter-js"
|
name = "dioxus-interpreter-js"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dioxus-core",
|
"dioxus-core",
|
||||||
"dioxus-core-types",
|
"dioxus-core-types",
|
||||||
@@ -4200,7 +4203,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-isrg"
|
name = "dioxus-isrg"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"http 1.3.1",
|
"http 1.3.1",
|
||||||
@@ -4213,7 +4216,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-lib"
|
name = "dioxus-lib"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dioxus",
|
"dioxus",
|
||||||
"dioxus-config-macro",
|
"dioxus-config-macro",
|
||||||
@@ -4230,7 +4233,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-liveview"
|
name = "dioxus-liveview"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum 0.8.4",
|
"axum 0.8.4",
|
||||||
"dioxus",
|
"dioxus",
|
||||||
@@ -4258,7 +4261,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-logger"
|
name = "dioxus-logger"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"console_error_panic_hook",
|
"console_error_panic_hook",
|
||||||
"dioxus",
|
"dioxus",
|
||||||
@@ -4270,7 +4273,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-mobile"
|
name = "dioxus-mobile"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dioxus-cli-config",
|
"dioxus-cli-config",
|
||||||
"dioxus-desktop",
|
"dioxus-desktop",
|
||||||
@@ -4282,7 +4285,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-native"
|
name = "dioxus-native"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"blitz-dom",
|
"blitz-dom",
|
||||||
"blitz-net",
|
"blitz-net",
|
||||||
@@ -4377,7 +4380,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-router"
|
name = "dioxus-router"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum 0.8.4",
|
"axum 0.8.4",
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
@@ -4400,7 +4403,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-router-macro"
|
name = "dioxus-router-macro"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base16",
|
"base16",
|
||||||
"digest",
|
"digest",
|
||||||
@@ -4414,7 +4417,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-rsx"
|
name = "dioxus-rsx"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"prettier-please",
|
"prettier-please",
|
||||||
"prettyplease",
|
"prettyplease",
|
||||||
@@ -4426,7 +4429,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-rsx-hotreload"
|
name = "dioxus-rsx-hotreload"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dioxus-core",
|
"dioxus-core",
|
||||||
"dioxus-core-types",
|
"dioxus-core-types",
|
||||||
@@ -4441,7 +4444,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-rsx-rosetta"
|
name = "dioxus-rsx-rosetta"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"convert_case 0.8.0",
|
"convert_case 0.8.0",
|
||||||
"dioxus-autofmt",
|
"dioxus-autofmt",
|
||||||
@@ -4457,7 +4460,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-server"
|
name = "dioxus-server"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"aws-lc-rs",
|
"aws-lc-rs",
|
||||||
@@ -4507,7 +4510,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-signals"
|
name = "dioxus-signals"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dioxus",
|
"dioxus",
|
||||||
"dioxus-core",
|
"dioxus-core",
|
||||||
@@ -4528,7 +4531,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-ssr"
|
name = "dioxus-ssr"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"askama_escape",
|
"askama_escape",
|
||||||
"dioxus",
|
"dioxus",
|
||||||
@@ -4547,7 +4550,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-web"
|
name = "dioxus-web"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"ciborium",
|
"ciborium",
|
||||||
@@ -4585,7 +4588,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus_server_macro"
|
name = "dioxus_server_macro"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum 0.8.4",
|
"axum 0.8.4",
|
||||||
"dioxus",
|
"dioxus",
|
||||||
@@ -4854,6 +4857,7 @@ dependencies = [
|
|||||||
"ed25519",
|
"ed25519",
|
||||||
"serde",
|
"serde",
|
||||||
"sha2",
|
"sha2",
|
||||||
|
"signature",
|
||||||
"subtle",
|
"subtle",
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
@@ -5822,7 +5826,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "generational-box"
|
name = "generational-box"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"criterion",
|
"criterion",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
@@ -8126,7 +8130,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy-js-bundle"
|
name = "lazy-js-bundle"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
@@ -8578,7 +8582,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "manganis"
|
name = "manganis"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"const-serialize",
|
"const-serialize",
|
||||||
"manganis-core",
|
"manganis-core",
|
||||||
@@ -8587,7 +8591,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "manganis-core"
|
name = "manganis-core"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"const-serialize",
|
"const-serialize",
|
||||||
"dioxus",
|
"dioxus",
|
||||||
@@ -8599,7 +8603,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "manganis-macro"
|
name = "manganis-macro"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dunce",
|
"dunce",
|
||||||
"macro-string",
|
"macro-string",
|
||||||
@@ -12168,6 +12172,41 @@ dependencies = [
|
|||||||
"to_shmem_derive",
|
"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]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "1.0.26"
|
version = "1.0.26"
|
||||||
@@ -13414,7 +13453,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "subsecond"
|
name = "subsecond"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -13431,7 +13470,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "subsecond-types"
|
name = "subsecond-types"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
@@ -13463,7 +13502,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "suspense-carousel"
|
name = "suspense-carousel"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-std",
|
"async-std",
|
||||||
"dioxus",
|
"dioxus",
|
||||||
@@ -15849,7 +15888,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-split"
|
name = "wasm-split"
|
||||||
version = "0.1.0"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-once-cell",
|
"async-once-cell",
|
||||||
"wasm-split-macro",
|
"wasm-split-macro",
|
||||||
@@ -15857,7 +15896,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-split-cli"
|
name = "wasm-split-cli"
|
||||||
version = "0.1.0"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"clap",
|
"clap",
|
||||||
@@ -15891,7 +15930,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-split-macro"
|
name = "wasm-split-macro"
|
||||||
version = "0.1.0"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base16",
|
"base16",
|
||||||
"digest",
|
"digest",
|
||||||
@@ -15916,7 +15955,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-used"
|
name = "wasm-used"
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"id-arena",
|
"id-arena",
|
||||||
"tracing",
|
"tracing",
|
||||||
@@ -17737,6 +17776,7 @@ dependencies = [
|
|||||||
"flate2",
|
"flate2",
|
||||||
"indexmap 2.9.0",
|
"indexmap 2.9.0",
|
||||||
"memchr",
|
"memchr",
|
||||||
|
"time",
|
||||||
"zopfli",
|
"zopfli",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -17751,6 +17791,17 @@ dependencies = [
|
|||||||
"thiserror 1.0.69",
|
"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]]
|
[[package]]
|
||||||
name = "zopfli"
|
name = "zopfli"
|
||||||
version = "0.8.2"
|
version = "0.8.2"
|
||||||
|
|||||||
+56
-56
@@ -127,71 +127,71 @@ members = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
|
|
||||||
# dependencies that are shared across packages
|
# dependencies that are shared across packages
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
dioxus = { path = "packages/dioxus", version = "0.6.2" }
|
dioxus = { path = "packages/dioxus", version = "0.7.0-alpha.0" }
|
||||||
dioxus-lib = { path = "packages/dioxus-lib", version = "0.6.2" }
|
dioxus-lib = { path = "packages/dioxus-lib", version = "0.7.0-alpha.0" }
|
||||||
dioxus-core = { path = "packages/core", version = "0.6.2" }
|
dioxus-core = { path = "packages/core", version = "0.7.0-alpha.0" }
|
||||||
dioxus-core-types = { path = "packages/core-types", version = "0.6.2" }
|
dioxus-core-types = { path = "packages/core-types", version = "0.7.0-alpha.0" }
|
||||||
dioxus-core-macro = { path = "packages/core-macro", version = "0.6.2" }
|
dioxus-core-macro = { path = "packages/core-macro", version = "0.7.0-alpha.0" }
|
||||||
dioxus-config-macro = { path = "packages/config-macro", version = "0.6.2" }
|
dioxus-config-macro = { path = "packages/config-macro", version = "0.7.0-alpha.0" }
|
||||||
dioxus-router = { path = "packages/router", version = "0.6.2" }
|
dioxus-router = { path = "packages/router", version = "0.7.0-alpha.0" }
|
||||||
dioxus-router-macro = { path = "packages/router-macro", version = "0.6.2" }
|
dioxus-router-macro = { path = "packages/router-macro", version = "0.7.0-alpha.0" }
|
||||||
dioxus-document = { path = "packages/document", version = "0.6.2", default-features = false }
|
dioxus-document = { path = "packages/document", version = "0.7.0-alpha.0", default-features = false }
|
||||||
dioxus-history = { path = "packages/history", version = "0.6.2", default-features = false }
|
dioxus-history = { path = "packages/history", version = "0.7.0-alpha.0", default-features = false }
|
||||||
dioxus-html = { path = "packages/html", version = "0.6.2", 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.6.2" }
|
dioxus-html-internal-macro = { path = "packages/html-internal-macro", version = "0.7.0-alpha.0" }
|
||||||
dioxus-hooks = { path = "packages/hooks", version = "0.6.2" }
|
dioxus-hooks = { path = "packages/hooks", version = "0.7.0-alpha.0" }
|
||||||
dioxus-web = { path = "packages/web", version = "0.6.2", default-features = false }
|
dioxus-web = { path = "packages/web", version = "0.7.0-alpha.0", default-features = false }
|
||||||
dioxus-isrg = { path = "packages/isrg", version = "0.6.2" }
|
dioxus-isrg = { path = "packages/isrg", version = "0.7.0-alpha.0" }
|
||||||
dioxus-ssr = { path = "packages/ssr", version = "0.6.2", default-features = false }
|
dioxus-ssr = { path = "packages/ssr", version = "0.7.0-alpha.0", default-features = false }
|
||||||
dioxus-desktop = { path = "packages/desktop", version = "0.6.2", default-features = false }
|
dioxus-desktop = { path = "packages/desktop", version = "0.7.0-alpha.0", default-features = false }
|
||||||
dioxus-mobile = { path = "packages/mobile", version = "0.6.2" }
|
dioxus-mobile = { path = "packages/mobile", version = "0.7.0-alpha.0" }
|
||||||
dioxus-interpreter-js = { path = "packages/interpreter", version = "0.6.2" }
|
dioxus-interpreter-js = { path = "packages/interpreter", version = "0.7.0-alpha.0" }
|
||||||
dioxus-liveview = { path = "packages/liveview", version = "0.6.2" }
|
dioxus-liveview = { path = "packages/liveview", version = "0.7.0-alpha.0" }
|
||||||
dioxus-autofmt = { path = "packages/autofmt", version = "0.6.2" }
|
dioxus-autofmt = { path = "packages/autofmt", version = "0.7.0-alpha.0" }
|
||||||
dioxus-check = { path = "packages/check", version = "0.6.2" }
|
dioxus-check = { path = "packages/check", version = "0.7.0-alpha.0" }
|
||||||
dioxus-rsx = { path = "packages/rsx", version = "0.6.2" }
|
dioxus-rsx = { path = "packages/rsx", version = "0.7.0-alpha.0" }
|
||||||
dioxus-rsx-hotreload = { path = "packages/rsx-hotreload", version = "0.6.2" }
|
dioxus-rsx-hotreload = { path = "packages/rsx-hotreload", version = "0.7.0-alpha.0" }
|
||||||
dioxus-rsx-rosetta = { path = "packages/rsx-rosetta", version = "0.6.2" }
|
dioxus-rsx-rosetta = { path = "packages/rsx-rosetta", version = "0.7.0-alpha.0" }
|
||||||
dioxus-signals = { path = "packages/signals", version = "0.6.2" }
|
dioxus-signals = { path = "packages/signals", version = "0.7.0-alpha.0" }
|
||||||
dioxus-cli-config = { path = "packages/cli-config", version = "0.6.2" }
|
dioxus-cli-config = { path = "packages/cli-config", version = "0.7.0-alpha.0" }
|
||||||
dioxus-cli-opt = { path = "packages/cli-opt", version = "0.6.2" }
|
dioxus-cli-opt = { path = "packages/cli-opt", version = "0.7.0-alpha.0" }
|
||||||
dioxus-devtools = { path = "packages/devtools", version = "0.6.2" }
|
dioxus-devtools = { path = "packages/devtools", version = "0.7.0-alpha.0" }
|
||||||
dioxus-devtools-types = { path = "packages/devtools-types", version = "0.6.2" }
|
dioxus-devtools-types = { path = "packages/devtools-types", version = "0.7.0-alpha.0" }
|
||||||
dioxus-server = { path = "packages/server", version = "0.6.2" }
|
dioxus-server = { path = "packages/server", version = "0.7.0-alpha.0" }
|
||||||
dioxus-fullstack = { path = "packages/fullstack", version = "0.6.2" }
|
dioxus-fullstack = { path = "packages/fullstack", version = "0.7.0-alpha.0" }
|
||||||
dioxus-fullstack-hooks = { path = "packages/fullstack-hooks", version = "0.6.3" }
|
dioxus-fullstack-hooks = { path = "packages/fullstack-hooks", version = "0.7.0-alpha.0" }
|
||||||
dioxus-fullstack-protocol = { path = "packages/fullstack-protocol", version = "0.6.3" }
|
dioxus-fullstack-protocol = { path = "packages/fullstack-protocol", version = "0.7.0-alpha.0" }
|
||||||
dioxus_server_macro = { path = "packages/server-macro", version = "0.6.2", default-features = false }
|
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.6.2" }
|
dioxus-dx-wire-format = { path = "packages/dx-wire-format", version = "0.7.0-alpha.0" }
|
||||||
dioxus-logger = { path = "packages/logger", version = "0.6.2" }
|
dioxus-logger = { path = "packages/logger", version = "0.7.0-alpha.0" }
|
||||||
dioxus-native = { path = "packages/native", version = "0.6.2" }
|
dioxus-native = { path = "packages/native", version = "0.7.0-alpha.0" }
|
||||||
dioxus-asset-resolver = { path = "packages/asset-resolver", version = "0.6.2" }
|
dioxus-asset-resolver = { path = "packages/asset-resolver", version = "0.7.0-alpha.0" }
|
||||||
dioxus-config-macros = { path = "packages/config-macros", version = "0.6.3" }
|
dioxus-config-macros = { path = "packages/config-macros", version = "0.7.0-alpha.0" }
|
||||||
const-serialize = { path = "packages/const-serialize", version = "0.6.2" }
|
const-serialize = { path = "packages/const-serialize", version = "0.7.0-alpha.0" }
|
||||||
const-serialize-macro = { path = "packages/const-serialize-macro", version = "0.6.2" }
|
const-serialize-macro = { path = "packages/const-serialize-macro", version = "0.7.0-alpha.0" }
|
||||||
generational-box = { path = "packages/generational-box", version = "0.6.2" }
|
generational-box = { path = "packages/generational-box", version = "0.7.0-alpha.0" }
|
||||||
lazy-js-bundle = { path = "packages/lazy-js-bundle", version = "0.6.2" }
|
lazy-js-bundle = { path = "packages/lazy-js-bundle", version = "0.7.0-alpha.0" }
|
||||||
|
|
||||||
# subsecond
|
# subsecond
|
||||||
subsecond-types = { path = "packages/subsecond/subsecond-types", version = "0.6.3" }
|
subsecond-types = { path = "packages/subsecond/subsecond-types", version = "0.7.0-alpha.0" }
|
||||||
subsecond = { path = "packages/subsecond/subsecond", version = "0.6.3" }
|
subsecond = { path = "packages/subsecond/subsecond", version = "0.7.0-alpha.0" }
|
||||||
|
|
||||||
# manganis
|
# manganis
|
||||||
manganis = { path = "packages/manganis/manganis", version = "0.6.2" }
|
manganis = { path = "packages/manganis/manganis", version = "0.7.0-alpha.0" }
|
||||||
manganis-core = { path = "packages/manganis/manganis-core", version = "0.6.2" }
|
manganis-core = { path = "packages/manganis/manganis-core", version = "0.7.0-alpha.0" }
|
||||||
manganis-macro = { path = "packages/manganis/manganis-macro", version = "0.6.2" }
|
manganis-macro = { path = "packages/manganis/manganis-macro", version = "0.7.0-alpha.0" }
|
||||||
|
|
||||||
# wasm-split
|
# wasm-split
|
||||||
wasm-split = { path = "packages/wasm-split/wasm-split", 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.1.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.1.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.1.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" }
|
warnings = { version = "0.2.1" }
|
||||||
|
|
||||||
# a fork of pretty please for tests - let's get off of this if we can!
|
# 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"]
|
keywords = ["dom", "ui", "gui", "react", "wasm"]
|
||||||
rust-version = "1.80.0"
|
rust-version = "1.80.0"
|
||||||
publish = false
|
publish = false
|
||||||
version = "0.6.3"
|
version = "0.7.0-alpha.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
reqwest = { workspace = true, features = ["json"], optional = true }
|
reqwest = { workspace = true, features = ["json"], optional = true }
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ ratatui = "ratatui"
|
|||||||
lits = "lits"
|
lits = "lits"
|
||||||
# https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/seeked_event
|
# https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/seeked_event
|
||||||
seeked = "seeked"
|
seeked = "seeked"
|
||||||
|
# https://developer.apple.com/forums/thread/108953
|
||||||
|
# udid = unique device identifier
|
||||||
|
udid = "udid"
|
||||||
|
|
||||||
[files]
|
[files]
|
||||||
extend-exclude = ["translations/*", "CHANGELOG.md", "*.js"]
|
extend-exclude = ["translations/*", "CHANGELOG.md", "*.js"]
|
||||||
@@ -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):
|
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
|
```bash
|
||||||
npx tailwindcss -i ./input.css -o ./public/tailwind.css --watch
|
npx tailwindcss -i ./tailwind.css -o ./public/tailwind.css --watch
|
||||||
dx serve
|
dx serve
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
File renamed without changes.
File renamed without changes.
+2
-1
@@ -3,4 +3,5 @@ exclude = ['file:///', 'https://github.com/DioxusLabs/dioxus/commit']
|
|||||||
exclude_path = ['target']
|
exclude_path = ['target']
|
||||||
no_progress = false
|
no_progress = false
|
||||||
cache = true
|
cache = true
|
||||||
max_cache_age = "10d"
|
max_cache_age = "10d"
|
||||||
|
accept = ["200..=204", "429"]
|
||||||
@@ -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
|
/// For reference, the devserver typically lives on `127.0.0.1:8080` and serves the devserver websocket
|
||||||
/// on `127.0.0.1:8080/_dioxus`.
|
/// on `127.0.0.1:8080/_dioxus`.
|
||||||
pub fn devserver_raw_addr() -> Option<SocketAddr> {
|
pub fn devserver_raw_addr() -> Option<SocketAddr> {
|
||||||
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") {
|
if cfg!(target_os = "android") {
|
||||||
// Since `adb reverse` is used for Android, the 127.0.0.1 will always be
|
// Since `adb reverse` is used for Android, the 127.0.0.1 will always be
|
||||||
// the correct IP address.
|
// the correct IP address.
|
||||||
|
let port = port.unwrap_or("8080".to_string());
|
||||||
return Some(format!("127.0.0.1:{}", port).parse().unwrap());
|
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()
|
format!("{}:{}", ip, port).parse().ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -136,6 +136,8 @@ backtrace = "0.3.74"
|
|||||||
ar = "0.9.0"
|
ar = "0.9.0"
|
||||||
wasm-bindgen-externref-xform = "0.2.100"
|
wasm-bindgen-externref-xform = "0.2.100"
|
||||||
pdb = "0.8.0"
|
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]
|
[build-dependencies]
|
||||||
built = { version = "0.7.5", features = ["git2"] }
|
built = { version = "0.7.5", features = ["git2"] }
|
||||||
@@ -162,10 +164,7 @@ name = "dx"
|
|||||||
escargot = "0.5"
|
escargot = "0.5"
|
||||||
|
|
||||||
[package.metadata.binstall]
|
[package.metadata.binstall]
|
||||||
pkg-url = "{ repo }/releases/download/v{ version }/dx-{ target }-v{ version }{ archive-suffix }"
|
pkg-url = "{ repo }/releases/download/v{ version }/dx-{ target }{ archive-suffix }"
|
||||||
pkg-fmt = "tgz"
|
|
||||||
|
|
||||||
[package.metadata.binstall.overrides.x86_64-pc-windows-msvc]
|
|
||||||
pkg-fmt = "zip"
|
pkg-fmt = "zip"
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<application android:hasCode="true" android:supportsRtl="true" android:icon="@mipmap/ic_launcher"
|
<application android:hasCode="true" android:supportsRtl="true" android:icon="@mipmap/ic_launcher"
|
||||||
android:extractNativeLibs="true"
|
android:extractNativeLibs="true"
|
||||||
@@ -16,5 +15,4 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -4,7 +4,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use dioxus_cli_opt::process_file_to;
|
use dioxus_cli_opt::process_file_to;
|
||||||
use futures_util::future::OptionFuture;
|
use futures_util::{future::OptionFuture, pin_mut, FutureExt};
|
||||||
use std::{
|
use std::{
|
||||||
env,
|
env,
|
||||||
time::{Duration, Instant, SystemTime},
|
time::{Duration, Instant, SystemTime},
|
||||||
@@ -617,13 +617,15 @@ impl AppBuilder {
|
|||||||
_ => vec![],
|
_ => vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::styles::{GLOW_STYLE, NOTE_STYLE};
|
||||||
|
|
||||||
let changed_file = changed_files.first().unwrap();
|
let changed_file = changed_files.first().unwrap();
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
"Hot-patching: {} took {:?}ms",
|
"Hot-patching: {NOTE_STYLE}{}{NOTE_STYLE:#} took {GLOW_STYLE}{:?}ms{GLOW_STYLE:#}",
|
||||||
changed_file
|
changed_file
|
||||||
.strip_prefix(std::env::current_dir().unwrap())
|
.display()
|
||||||
.unwrap_or(changed_file.as_path())
|
.to_string()
|
||||||
.display(),
|
.trim_start_matches(&self.build.crate_dir().display().to_string()),
|
||||||
SystemTime::now()
|
SystemTime::now()
|
||||||
.duration_since(res.time_start)
|
.duration_since(res.time_start)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@@ -704,7 +706,7 @@ impl AppBuilder {
|
|||||||
let target = dioxus_cli_config::android_session_cache_dir().join(bundled_name);
|
let target = dioxus_cli_config::android_session_cache_dir().join(bundled_name);
|
||||||
tracing::debug!("Pushing asset to device: {target:?}");
|
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("push")
|
||||||
.arg(changed_file)
|
.arg(changed_file)
|
||||||
.arg(&target)
|
.arg(&target)
|
||||||
@@ -1140,7 +1142,7 @@ We checked the folder: {}
|
|||||||
let adb = self.build.workspace.android_tools()?.adb.clone();
|
let adb = self.build.workspace.android_tools()?.adb.clone();
|
||||||
|
|
||||||
// Start backgrounded since .open() is called while in the arm of the top-level match
|
// Start backgrounded since .open() is called while in the arm of the top-level match
|
||||||
tokio::task::spawn(async move {
|
let _handle: JoinHandle<Result<()>> = tokio::task::spawn(async move {
|
||||||
// call `adb root` so we can push patches to the device
|
// call `adb root` so we can push patches to the device
|
||||||
if root {
|
if root {
|
||||||
if let Err(e) = Command::new(&adb).arg("root").output().await {
|
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}");
|
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
|
// Install
|
||||||
// adb install -r app-debug.apk
|
// adb install -r app-debug.apk
|
||||||
if let Err(e) = Command::new(&adb)
|
let res = Command::new(&adb)
|
||||||
.arg("install")
|
.arg("install")
|
||||||
.arg("-r")
|
.arg("-r")
|
||||||
.arg(apk_path)
|
.arg(apk_path)
|
||||||
.output()
|
.output()
|
||||||
.await
|
.await?;
|
||||||
{
|
let std_err = String::from_utf8_lossy(&res.stderr);
|
||||||
tracing::error!("Failed to install apk with `adb`: {e}");
|
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
|
// Write the env vars to a .env file in our session cache
|
||||||
let env_file = session_cache.join(".env");
|
let env_file = session_cache.join(".env");
|
||||||
let contents: String = envs
|
_ = std::fs::write(
|
||||||
.iter()
|
&env_file,
|
||||||
.map(|(key, value)| format!("{key}={value}"))
|
envs.iter()
|
||||||
.collect::<Vec<_>>()
|
.map(|(key, value)| format!("{key}={value}"))
|
||||||
.join("\n");
|
.collect::<Vec<_>>()
|
||||||
_ = std::fs::write(&env_file, contents);
|
.join("\n"),
|
||||||
|
);
|
||||||
|
|
||||||
// Push the env file to the device
|
// Push the env file to the device
|
||||||
if let Err(e) = tokio::process::Command::new(&adb)
|
Command::new(&adb)
|
||||||
.arg("push")
|
.arg("push")
|
||||||
.arg(env_file)
|
.arg(env_file)
|
||||||
.arg(dioxus_cli_config::android_session_cache_dir().join(".env"))
|
.arg(dioxus_cli_config::android_session_cache_dir().join(".env"))
|
||||||
.output()
|
.output()
|
||||||
.await
|
.await?;
|
||||||
.context("Failed to push asset to device")
|
|
||||||
{
|
|
||||||
tracing::error!("Failed to push .env file to device: {e}");
|
|
||||||
}
|
|
||||||
|
|
||||||
// eventually, use the user's MainActivity, not our MainActivity
|
// eventually, use the user's MainActivity, not our MainActivity
|
||||||
// adb shell am start -n dev.dioxus.main/dev.dioxus.main.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,);
|
let activity_name = format!("{}/dev.dioxus.main.MainActivity", full_mobile_app_name,);
|
||||||
|
let res = Command::new(&adb)
|
||||||
if let Err(e) = Command::new(&adb)
|
|
||||||
.arg("shell")
|
.arg("shell")
|
||||||
.arg("am")
|
.arg("am")
|
||||||
.arg("start")
|
.arg("start")
|
||||||
.arg("-n")
|
.arg("-n")
|
||||||
.arg(activity_name)
|
.arg(activity_name)
|
||||||
.output()
|
.output()
|
||||||
.await
|
.await?;
|
||||||
{
|
let std_err = String::from_utf8_lossy(res.stderr.trim_ascii());
|
||||||
tracing::error!("Failed to start app with `adb`: {e}");
|
if !std_err.is_empty() {
|
||||||
};
|
tracing::error!("Failed to start app with `adb`: {std_err}");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -329,7 +329,7 @@ use manganis::{AssetOptions, JsAssetOptions};
|
|||||||
use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};
|
use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashSet,
|
collections::{BTreeMap, HashSet},
|
||||||
io::Write,
|
io::Write,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
process::Stdio,
|
process::Stdio,
|
||||||
@@ -370,7 +370,7 @@ pub(crate) struct BuildRequest {
|
|||||||
pub(crate) platform: Platform,
|
pub(crate) platform: Platform,
|
||||||
pub(crate) enabled_platforms: Vec<Platform>,
|
pub(crate) enabled_platforms: Vec<Platform>,
|
||||||
pub(crate) triple: Triple,
|
pub(crate) triple: Triple,
|
||||||
pub(crate) _device: bool,
|
pub(crate) device: bool,
|
||||||
pub(crate) package: String,
|
pub(crate) package: String,
|
||||||
pub(crate) features: Vec<String>,
|
pub(crate) features: Vec<String>,
|
||||||
pub(crate) extra_cargo_args: Vec<String>,
|
pub(crate) extra_cargo_args: Vec<String>,
|
||||||
@@ -536,6 +536,10 @@ impl BuildRequest {
|
|||||||
// We collect all the platforms it enables first and then select based on the --platform arg
|
// We collect all the platforms it enables first and then select based on the --platform arg
|
||||||
let enabled_platforms =
|
let enabled_platforms =
|
||||||
Self::enabled_cargo_toml_platforms(main_package, args.no_default_features);
|
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 features = args.features.clone();
|
||||||
let mut no_default_features = args.no_default_features;
|
let mut no_default_features = args.no_default_features;
|
||||||
@@ -552,6 +556,7 @@ impl BuildRequest {
|
|||||||
platform
|
platform
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
None if !using_dioxus_explicitly => Platform::autodetect_from_cargo_feature("desktop").unwrap(),
|
||||||
None => match enabled_platforms.len() {
|
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()),
|
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],
|
1 => enabled_platforms[0],
|
||||||
@@ -565,7 +570,9 @@ impl BuildRequest {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Add any features required to turn on the client
|
// 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
|
// 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
|
// 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!(
|
tracing::debug!(
|
||||||
r#"Log Files:
|
r#"Log Files:
|
||||||
link_args_file: {},
|
• link_args_file: {},
|
||||||
link_err_file: {},
|
• link_err_file: {},
|
||||||
rustc_wrapper_args_file: {},
|
• rustc_wrapper_args_file: {},
|
||||||
session_cache_dir: {}"#,
|
• session_cache_dir: {}"#,
|
||||||
link_args_file.path().display(),
|
link_args_file.path().display(),
|
||||||
link_err_file.path().display(),
|
link_err_file.path().display(),
|
||||||
rustc_wrapper_args_file.path().display(),
|
rustc_wrapper_args_file.path().display(),
|
||||||
@@ -684,7 +691,7 @@ session_cache_dir: {}"#,
|
|||||||
crate_target,
|
crate_target,
|
||||||
profile,
|
profile,
|
||||||
triple,
|
triple,
|
||||||
_device: device,
|
device,
|
||||||
workspace,
|
workspace,
|
||||||
config,
|
config,
|
||||||
enabled_platforms,
|
enabled_platforms,
|
||||||
@@ -886,7 +893,8 @@ session_cache_dir: {}"#,
|
|||||||
let time_end = SystemTime::now();
|
let time_end = SystemTime::now();
|
||||||
let mode = ctx.mode.clone();
|
let mode = ctx.mode.clone();
|
||||||
let platform = self.platform;
|
let platform = self.platform;
|
||||||
tracing::debug!("Build completed successfully - output location: {:?}", exe);
|
|
||||||
|
tracing::debug!("Build completed successfully: {:?}", exe);
|
||||||
|
|
||||||
Ok(BuildArtifacts {
|
Ok(BuildArtifacts {
|
||||||
time_end,
|
time_end,
|
||||||
@@ -905,8 +913,6 @@ session_cache_dir: {}"#,
|
|||||||
/// This uses "known paths" that have stayed relatively stable during cargo's lifetime.
|
/// 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.
|
/// 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<AssetManifest> {
|
fn collect_assets(&self, exe: &Path, ctx: &BuildContext) -> Result<AssetManifest> {
|
||||||
tracing::debug!("Collecting assets from exe at {} ...", exe.display());
|
|
||||||
|
|
||||||
// walk every file in the incremental cache dir, reading and inserting items into the manifest.
|
// walk every file in the incremental cache dir, reading and inserting items into the manifest.
|
||||||
let mut manifest = AssetManifest::default();
|
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
|
// 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
|
// 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:
|
// Also, some flags in darwin land might become deprecated, need to be super conservative:
|
||||||
// - https://developer.apple.com/forums/thread/773907
|
// - 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
|
// And now we can run the linker with our new args
|
||||||
let linker = self.select_linker()?;
|
let linker = self.select_linker()?;
|
||||||
|
|
||||||
let out_exe = self.patch_exe(artifacts.time_start);
|
let out_exe = self.patch_exe(artifacts.time_start);
|
||||||
let out_arg = match self.triple.operating_system {
|
let out_arg = match self.triple.operating_system {
|
||||||
OperatingSystem::Windows => vec![format!("/OUT:{}", out_exe.display())],
|
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
|
// 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.
|
// 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 => {
|
OperatingSystem::Unknown if self.platform == Platform::Web => {
|
||||||
out_args.extend([
|
out_args.extend([
|
||||||
"--fatal-warnings".to_string(),
|
"--fatal-warnings".to_string(),
|
||||||
@@ -1390,7 +1402,6 @@ session_cache_dir: {}"#,
|
|||||||
"/PDBALTPATH:%_PDB%".to_string(),
|
"/PDBALTPATH:%_PDB%".to_string(),
|
||||||
"/EXPORT:main".to_string(),
|
"/EXPORT:main".to_string(),
|
||||||
"/HIGHENTROPYVA:NO".to_string(),
|
"/HIGHENTROPYVA:NO".to_string(),
|
||||||
// "/SUBSYSTEM:WINDOWS".to_string(),
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1764,7 +1775,6 @@ session_cache_dir: {}"#,
|
|||||||
cmd.current_dir(self.workspace_dir());
|
cmd.current_dir(self.workspace_dir());
|
||||||
cmd.env_clear();
|
cmd.env_clear();
|
||||||
cmd.args(rustc_args.args[1..].iter());
|
cmd.args(rustc_args.args[1..].iter());
|
||||||
cmd.envs(rustc_args.envs.iter().cloned());
|
|
||||||
cmd.env_remove("RUSTC_WORKSPACE_WRAPPER");
|
cmd.env_remove("RUSTC_WORKSPACE_WRAPPER");
|
||||||
cmd.env_remove("RUSTC_WRAPPER");
|
cmd.env_remove("RUSTC_WRAPPER");
|
||||||
cmd.env_remove(DX_RUSTC_WRAPPER_ENV_VAR);
|
cmd.env_remove(DX_RUSTC_WRAPPER_ENV_VAR);
|
||||||
@@ -1775,7 +1785,11 @@ session_cache_dir: {}"#,
|
|||||||
cmd.arg("-Crelocation-model=pic");
|
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)
|
Ok(cmd)
|
||||||
}
|
}
|
||||||
@@ -1800,8 +1814,6 @@ session_cache_dir: {}"#,
|
|||||||
.args(self.cargo_build_arguments(ctx))
|
.args(self.cargo_build_arguments(ctx))
|
||||||
.envs(self.cargo_build_env_vars(ctx)?);
|
.envs(self.cargo_build_env_vars(ctx)?);
|
||||||
|
|
||||||
tracing::trace!("Cargo command: {:#?}", cmd);
|
|
||||||
|
|
||||||
if ctx.mode == BuildMode::Fat {
|
if ctx.mode == BuildMode::Fat {
|
||||||
cmd.env(
|
cmd.env(
|
||||||
DX_RUSTC_WRAPPER_ENV_VAR,
|
DX_RUSTC_WRAPPER_ENV_VAR,
|
||||||
@@ -1816,6 +1828,8 @@ session_cache_dir: {}"#,
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tracing::debug!("Cargo: {:#?}", cmd);
|
||||||
|
|
||||||
Ok(cmd)
|
Ok(cmd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1942,14 +1956,7 @@ session_cache_dir: {}"#,
|
|||||||
//
|
//
|
||||||
// https://github.com/WebAssembly/tool-conventions/blob/main/DynamicLinking.md
|
// https://github.com/WebAssembly/tool-conventions/blob/main/DynamicLinking.md
|
||||||
//
|
//
|
||||||
// The trickiest one here is -Crelocation-model=pic, which forces data symbols
|
// The tricky one is -Ctarget-cpu=mvp, which prevents rustc from generating externref
|
||||||
// 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
|
|
||||||
// entries.
|
// entries.
|
||||||
//
|
//
|
||||||
// https://blog.rust-lang.org/2024/09/24/webassembly-targets-change-in-default-target-features/#disabling-on-by-default-webassembly-proposals
|
// 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
|
if self.platform == Platform::Web
|
||||||
|| self.triple.operating_system == OperatingSystem::Wasi
|
|| self.triple.operating_system == OperatingSystem::Wasi
|
||||||
{
|
{
|
||||||
// cargo_args.push("-Crelocation-model=pic".into());
|
|
||||||
cargo_args.push("-Ctarget-cpu=mvp".into());
|
cargo_args.push("-Ctarget-cpu=mvp".into());
|
||||||
cargo_args.push("-Clink-arg=--no-gc-sections".into());
|
cargo_args.push("-Clink-arg=--no-gc-sections".into());
|
||||||
cargo_args.push("-Clink-arg=--growable-table".into());
|
cargo_args.push("-Clink-arg=--growable-table".into());
|
||||||
@@ -2324,12 +2330,19 @@ session_cache_dir: {}"#,
|
|||||||
app.join("proguard-rules.pro"),
|
app.join("proguard-rules.pro"),
|
||||||
include_bytes!("../../assets/android/gen/app/proguard-rules.pro"),
|
include_bytes!("../../assets/android/gen/app/proguard-rules.pro"),
|
||||||
)?;
|
)?;
|
||||||
write(
|
|
||||||
app.join("src").join("main").join("AndroidManifest.xml"),
|
let manifest_xml = match self.config.application.android_manifest.as_deref() {
|
||||||
hbs.render_template(
|
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"),
|
include_str!("../../assets/android/gen/app/src/main/AndroidManifest.xml.hbs"),
|
||||||
&hbs_data,
|
&hbs_data,
|
||||||
)?,
|
)?,
|
||||||
|
};
|
||||||
|
|
||||||
|
write(
|
||||||
|
app.join("src").join("main").join("AndroidManifest.xml"),
|
||||||
|
manifest_xml,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Write the main activity manually since tao dropped support for it
|
// Write the main activity manually since tao dropped support for it
|
||||||
@@ -2657,8 +2670,6 @@ session_cache_dir: {}"#,
|
|||||||
return platforms;
|
return platforms;
|
||||||
};
|
};
|
||||||
|
|
||||||
tracing::debug!("Default features: {default:?}");
|
|
||||||
|
|
||||||
// we only trace features 1 level deep..
|
// we only trace features 1 level deep..
|
||||||
for feature in default.iter() {
|
for feature in default.iter() {
|
||||||
// If the user directly specified a platform we can just use that.
|
// If the user directly specified a platform we can just use that.
|
||||||
@@ -2688,8 +2699,6 @@ session_cache_dir: {}"#,
|
|||||||
platforms.sort();
|
platforms.sort();
|
||||||
platforms.dedup();
|
platforms.dedup();
|
||||||
|
|
||||||
tracing::debug!("Default platforms: {platforms:?}");
|
|
||||||
|
|
||||||
platforms
|
platforms
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2876,13 +2885,15 @@ session_cache_dir: {}"#,
|
|||||||
// If pre-compressing is enabled, we can pre_compress the wasm-bindgen output
|
// If pre-compressing is enabled, we can pre_compress the wasm-bindgen output
|
||||||
let pre_compress = self.should_pre_compress_web_assets(self.release);
|
let pre_compress = self.should_pre_compress_web_assets(self.release);
|
||||||
|
|
||||||
ctx.status_compressing_assets();
|
if pre_compress {
|
||||||
let asset_dir = self.asset_dir();
|
ctx.status_compressing_assets();
|
||||||
tokio::task::spawn_blocking(move || {
|
let asset_dir = self.asset_dir();
|
||||||
crate::fastfs::pre_compress_folder(&asset_dir, pre_compress)
|
tokio::task::spawn_blocking(move || {
|
||||||
})
|
crate::fastfs::pre_compress_folder(&asset_dir, pre_compress)
|
||||||
.await
|
})
|
||||||
.unwrap()?;
|
.await
|
||||||
|
.unwrap()?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Platform::MacOS => {}
|
Platform::MacOS => {}
|
||||||
Platform::Windows => {}
|
Platform::Windows => {}
|
||||||
@@ -3132,6 +3143,22 @@ session_cache_dir: {}"#,
|
|||||||
pub executable_name: String,
|
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 {
|
match platform {
|
||||||
Platform::MacOS => handlebars::Handlebars::new()
|
Platform::MacOS => handlebars::Handlebars::new()
|
||||||
.render_template(
|
.render_template(
|
||||||
@@ -3273,9 +3300,15 @@ session_cache_dir: {}"#,
|
|||||||
create_dir_all(self.exe_dir())?;
|
create_dir_all(self.exe_dir())?;
|
||||||
create_dir_all(self.asset_dir())?;
|
create_dir_all(self.asset_dir())?;
|
||||||
|
|
||||||
tracing::debug!("Initialized Root dir: {:?}", self.root_dir());
|
tracing::debug!(
|
||||||
tracing::debug!("Initialized Exe dir: {:?}", self.exe_dir());
|
r#"Initialized build dirs:
|
||||||
tracing::debug!("Initialized Asset dir: {:?}", self.asset_dir());
|
• 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
|
// 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
|
// 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
|
/// 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.
|
/// is in place, and we don't want to slow down subsequent builds.
|
||||||
pub(crate) async fn verify_tooling(&self, ctx: &BuildContext) -> Result<()> {
|
pub(crate) async fn verify_tooling(&self, ctx: &BuildContext) -> Result<()> {
|
||||||
tracing::debug!("Verifying tooling...");
|
|
||||||
ctx.status_installing_tooling();
|
ctx.status_installing_tooling();
|
||||||
|
|
||||||
self
|
self
|
||||||
@@ -3768,4 +3800,116 @@ r#" <script>
|
|||||||
.to_path_buf()
|
.to_path_buf()
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn start_simulators(&self) -> Result<()> {
|
||||||
|
if self.device {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.platform {
|
||||||
|
// Boot an iOS simulator if one is not already running.
|
||||||
|
//
|
||||||
|
// We always choose the most recently opened simulator based on the xcrun list.
|
||||||
|
// Note that simulators can be running but the simulator app itself is not open.
|
||||||
|
// Calling `open::that` is always fine, even on running apps, since apps are singletons.
|
||||||
|
Platform::Ios => {
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
struct XcrunListJson {
|
||||||
|
// "com.apple.CoreSimulator.SimRuntime.iOS-18-4": [{}, {}, {}]
|
||||||
|
devices: BTreeMap<String, Vec<XcrunDevice>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
struct XcrunDevice {
|
||||||
|
#[serde(rename = "lastBootedAt")]
|
||||||
|
last_booted_at: Option<String>,
|
||||||
|
udid: String,
|
||||||
|
name: String,
|
||||||
|
state: String,
|
||||||
|
}
|
||||||
|
let xcrun_list = Command::new("xcrun")
|
||||||
|
.arg("simctl")
|
||||||
|
.arg("list")
|
||||||
|
.arg("-j")
|
||||||
|
.output()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let as_str = String::from_utf8_lossy(&xcrun_list.stdout);
|
||||||
|
let xcrun_list_json = serde_json::from_str::<XcrunListJson>(as_str.trim());
|
||||||
|
if let Ok(xcrun_list_json) = xcrun_list_json {
|
||||||
|
if xcrun_list_json.devices.is_empty() {
|
||||||
|
tracing::warn!(
|
||||||
|
"No iOS sdks installed found. Please install the iOS SDK in Xcode."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some((_rt, devices)) = xcrun_list_json.devices.iter().next() {
|
||||||
|
if devices.iter().all(|device| device.state != "Booted") {
|
||||||
|
let last_booted =
|
||||||
|
devices
|
||||||
|
.iter()
|
||||||
|
.max_by_key(|device| match device.last_booted_at {
|
||||||
|
Some(ref last_booted) => last_booted,
|
||||||
|
None => "2000-01-01T01:01:01Z",
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(device) = last_booted {
|
||||||
|
tracing::info!("Booting iOS simulator: \"{}\"", device.name);
|
||||||
|
Command::new("xcrun")
|
||||||
|
.arg("simctl")
|
||||||
|
.arg("boot")
|
||||||
|
.arg(&device.udid)
|
||||||
|
.output()
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let path_to_xcode = Command::new("xcode-select")
|
||||||
|
.arg("--print-path")
|
||||||
|
.output()
|
||||||
|
.await?;
|
||||||
|
let path_to_xcode: PathBuf = String::from_utf8_lossy(&path_to_xcode.stdout)
|
||||||
|
.as_ref()
|
||||||
|
.trim()
|
||||||
|
.into();
|
||||||
|
let path_to_sim = path_to_xcode.join("Applications").join("Simulator.app");
|
||||||
|
open::that(path_to_sim)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Platform::Android => {
|
||||||
|
let tools = self.workspace.android_tools()?;
|
||||||
|
tokio::spawn(async move {
|
||||||
|
let emulator = tools.emulator();
|
||||||
|
let avds = Command::new(&emulator)
|
||||||
|
.arg("-list-avds")
|
||||||
|
.output()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let avds = String::from_utf8_lossy(&avds.stdout);
|
||||||
|
let avd = avds.trim().lines().next().map(|s| s.trim().to_string());
|
||||||
|
if let Some(avd) = avd {
|
||||||
|
tracing::info!("Booting Android emulator: \"{avd}\"");
|
||||||
|
Command::new(&emulator)
|
||||||
|
.arg("-avd")
|
||||||
|
.arg(avd)
|
||||||
|
.args(["-netdelay", "none", "-netspeed", "full"])
|
||||||
|
.stdout(std::process::Stdio::null()) // prevent accumulating huge amounts of mem usage
|
||||||
|
.stderr(std::process::Stdio::null()) // prevent accumulating huge amounts of mem usage
|
||||||
|
.output()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
} else {
|
||||||
|
tracing::warn!("No Android emulators found. Please create one using `emulator -avd <name>`");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
// nothing - maybe on the web we should open the browser?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -11,6 +11,7 @@ use tokio::process::Command;
|
|||||||
/// https://gist.github.com/Pulimet/5013acf2cd5b28e55036c82c91bd56d8?permalink_comment_id=3678614
|
/// https://gist.github.com/Pulimet/5013acf2cd5b28e55036c82c91bd56d8?permalink_comment_id=3678614
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) struct AndroidTools {
|
pub(crate) struct AndroidTools {
|
||||||
|
pub(crate) sdk: Option<PathBuf>,
|
||||||
pub(crate) ndk: PathBuf,
|
pub(crate) ndk: PathBuf,
|
||||||
pub(crate) adb: PathBuf,
|
pub(crate) adb: PathBuf,
|
||||||
pub(crate) java_home: Option<PathBuf>,
|
pub(crate) java_home: Option<PathBuf>,
|
||||||
@@ -114,6 +115,7 @@ pub fn get_android_tools() -> Option<Arc<AndroidTools>> {
|
|||||||
ndk,
|
ndk,
|
||||||
adb,
|
adb,
|
||||||
java_home,
|
java_home,
|
||||||
|
sdk,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,6 +170,18 @@ impl AndroidTools {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn sdk(&self) -> PathBuf {
|
||||||
|
// /Users/jonathankelley/Library/Android/sdk/ndk/25.2/... (25.2 is the ndk here)
|
||||||
|
// /Users/jonathankelley/Library/Android/sdk/
|
||||||
|
self.sdk
|
||||||
|
.clone()
|
||||||
|
.unwrap_or_else(|| self.ndk.parent().unwrap().parent().unwrap().to_path_buf())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn emulator(&self) -> PathBuf {
|
||||||
|
self.sdk().join("emulator").join("emulator")
|
||||||
|
}
|
||||||
|
|
||||||
// todo(jon): this should be configurable
|
// todo(jon): this should be configurable
|
||||||
pub(crate) fn min_sdk_version(&self) -> u32 {
|
pub(crate) fn min_sdk_version(&self) -> u32 {
|
||||||
24
|
24
|
||||||
@@ -230,8 +244,11 @@ impl AndroidTools {
|
|||||||
"x86_64" => {
|
"x86_64" => {
|
||||||
triple.architecture = Architecture::X86_64;
|
triple.architecture = Architecture::X86_64;
|
||||||
}
|
}
|
||||||
|
"" => {
|
||||||
|
tracing::debug!("No device running - probably waiting for emulator");
|
||||||
|
}
|
||||||
other => {
|
other => {
|
||||||
tracing::warn!("Unknown architecture from adb: {other}");
|
tracing::debug!("Unknown architecture from adb: {other}");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Ok(Err(err)) => {
|
Ok(Err(err)) => {
|
||||||
@@ -248,10 +265,9 @@ impl AndroidTools {
|
|||||||
|
|
||||||
fn var_or_debug(name: &str) -> Option<PathBuf> {
|
fn var_or_debug(name: &str) -> Option<PathBuf> {
|
||||||
use std::env::var;
|
use std::env::var;
|
||||||
use tracing::debug;
|
|
||||||
|
|
||||||
var(name)
|
var(name)
|
||||||
.inspect_err(|_| debug!("{name} not set"))
|
.inspect_err(|_| tracing::trace!("{name} not set"))
|
||||||
.ok()
|
.ok()
|
||||||
.map(PathBuf::from)
|
.map(PathBuf::from)
|
||||||
}
|
}
|
||||||
@@ -89,6 +89,9 @@ impl BuildArgs {
|
|||||||
pub async fn into_targets(self) -> Result<BuildTargets> {
|
pub async fn into_targets(self) -> Result<BuildTargets> {
|
||||||
let workspace = Workspace::current().await?;
|
let workspace = Workspace::current().await?;
|
||||||
|
|
||||||
|
// do some logging to ensure dx matches the dioxus version since we're not always API compatible
|
||||||
|
workspace.check_dioxus_version_against_cli();
|
||||||
|
|
||||||
let mut server = None;
|
let mut server = None;
|
||||||
|
|
||||||
let client = match self.targets {
|
let client = match self.targets {
|
||||||
|
|||||||
@@ -221,7 +221,7 @@ pub(crate) fn post_create(path: &Path) -> Result<()> {
|
|||||||
let mut file = std::fs::File::create(readme_path)?;
|
let mut file = std::fs::File::create(readme_path)?;
|
||||||
file.write_all(new_readme.as_bytes())?;
|
file.write_all(new_readme.as_bytes())?;
|
||||||
|
|
||||||
tracing::info!(dx_src = ?TraceSrc::Dev, "Generated project at {}\n\n`cd` to your project and run `dx serve` to start developing.\nIf using Tailwind, make sure to run the Tailwind CLI.\nMore information is available in the generated `README.md`.\n\nBuild cool things! ✌️", path.display());
|
tracing::info!(dx_src = ?TraceSrc::Dev, "Generated project at {}\n\n`cd` to your project and run `dx serve` to start developing.\nMore information is available in the generated `README.md`.\n\nBuild cool things! ✌️", path.display());
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
+59
-22
@@ -12,6 +12,7 @@ pub(crate) mod run;
|
|||||||
pub(crate) mod serve;
|
pub(crate) mod serve;
|
||||||
pub(crate) mod target;
|
pub(crate) mod target;
|
||||||
pub(crate) mod translate;
|
pub(crate) mod translate;
|
||||||
|
pub(crate) mod update;
|
||||||
pub(crate) mod verbosity;
|
pub(crate) mod verbosity;
|
||||||
|
|
||||||
pub(crate) use build::*;
|
pub(crate) use build::*;
|
||||||
@@ -20,6 +21,7 @@ pub(crate) use target::*;
|
|||||||
pub(crate) use verbosity::*;
|
pub(crate) use verbosity::*;
|
||||||
|
|
||||||
use crate::{error::Result, Error, StructuredOutput};
|
use crate::{error::Result, Error, StructuredOutput};
|
||||||
|
use clap::builder::styling::{AnsiColor, Effects, Style, Styles};
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use html_parser::Dom;
|
use html_parser::Dom;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
@@ -32,9 +34,10 @@ use std::{
|
|||||||
process::Command,
|
process::Command,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Build, Bundle & Ship Dioxus Apps.
|
/// Dioxus: build web, desktop, and mobile apps with a single codebase.
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[clap(name = "dioxus", version = VERSION.as_str())]
|
#[clap(name = "dioxus", version = VERSION.as_str())]
|
||||||
|
#[clap(styles = CARGO_STYLING)]
|
||||||
pub(crate) struct Cli {
|
pub(crate) struct Cli {
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
pub(crate) action: Commands,
|
pub(crate) action: Commands,
|
||||||
@@ -45,21 +48,29 @@ pub(crate) struct Cli {
|
|||||||
|
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
pub(crate) enum Commands {
|
pub(crate) enum Commands {
|
||||||
|
/// Create a new Dioxus project.
|
||||||
|
#[clap(name = "new")]
|
||||||
|
New(create::Create),
|
||||||
|
|
||||||
|
/// Build, watch, and serve the project.
|
||||||
|
#[clap(name = "serve")]
|
||||||
|
Serve(serve::ServeArgs),
|
||||||
|
|
||||||
|
/// Bundle the Dioxus app into a shippable object.
|
||||||
|
#[clap(name = "bundle")]
|
||||||
|
Bundle(bundle::Bundle),
|
||||||
|
|
||||||
/// Build the Dioxus project and all of its assets.
|
/// Build the Dioxus project and all of its assets.
|
||||||
#[clap(name = "build")]
|
#[clap(name = "build")]
|
||||||
Build(build::BuildArgs),
|
Build(build::BuildArgs),
|
||||||
|
|
||||||
/// Translate a source file into Dioxus code.
|
/// Run the project without any hotreloading.
|
||||||
#[clap(name = "translate")]
|
#[clap(name = "run")]
|
||||||
Translate(translate::Translate),
|
Run(run::RunArgs),
|
||||||
|
|
||||||
/// Build, watch & serve the Dioxus project and all of its assets.
|
/// Build the assets for a specific target.
|
||||||
#[clap(name = "serve")]
|
#[clap(name = "assets")]
|
||||||
Serve(serve::ServeArgs),
|
BuildAssets(build_assets::BuildAssets),
|
||||||
|
|
||||||
/// Create a new project for Dioxus.
|
|
||||||
#[clap(name = "new")]
|
|
||||||
New(create::Create),
|
|
||||||
|
|
||||||
/// Init a new project for Dioxus in the current directory (by default).
|
/// Init a new project for Dioxus in the current directory (by default).
|
||||||
/// Will attempt to keep your project in a good state.
|
/// Will attempt to keep your project in a good state.
|
||||||
@@ -70,9 +81,9 @@ pub(crate) enum Commands {
|
|||||||
#[clap(name = "clean")]
|
#[clap(name = "clean")]
|
||||||
Clean(clean::Clean),
|
Clean(clean::Clean),
|
||||||
|
|
||||||
/// Bundle the Dioxus app into a shippable object.
|
/// Translate a source file into Dioxus code.
|
||||||
#[clap(name = "bundle")]
|
#[clap(name = "translate")]
|
||||||
Bundle(bundle::Bundle),
|
Translate(translate::Translate),
|
||||||
|
|
||||||
/// Automatically format RSX.
|
/// Automatically format RSX.
|
||||||
#[clap(name = "fmt")]
|
#[clap(name = "fmt")]
|
||||||
@@ -82,18 +93,14 @@ pub(crate) enum Commands {
|
|||||||
#[clap(name = "check")]
|
#[clap(name = "check")]
|
||||||
Check(check::Check),
|
Check(check::Check),
|
||||||
|
|
||||||
/// Run the project without any hotreloading
|
|
||||||
#[clap(name = "run")]
|
|
||||||
Run(run::RunArgs),
|
|
||||||
|
|
||||||
/// Dioxus config file controls.
|
/// Dioxus config file controls.
|
||||||
#[clap(subcommand)]
|
#[clap(subcommand)]
|
||||||
#[clap(name = "config")]
|
#[clap(name = "config")]
|
||||||
Config(config::Config),
|
Config(config::Config),
|
||||||
|
|
||||||
/// Build the assets for a specific target.
|
/// Update the Dioxus CLI to the latest version.
|
||||||
#[clap(name = "assets")]
|
#[clap(name = "self-update")]
|
||||||
BuildAssets(build_assets::BuildAssets),
|
SelfUpdate(update::SelfUpdate),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Commands {
|
impl Display for Commands {
|
||||||
@@ -110,7 +117,8 @@ impl Display for Commands {
|
|||||||
Commands::Check(_) => write!(f, "check"),
|
Commands::Check(_) => write!(f, "check"),
|
||||||
Commands::Bundle(_) => write!(f, "bundle"),
|
Commands::Bundle(_) => write!(f, "bundle"),
|
||||||
Commands::Run(_) => write!(f, "run"),
|
Commands::Run(_) => write!(f, "run"),
|
||||||
Commands::BuildAssets(_) => write!(f, "build_assets"),
|
Commands::BuildAssets(_) => write!(f, "assets"),
|
||||||
|
Commands::SelfUpdate(_) => write!(f, "self-update"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -122,3 +130,32 @@ pub(crate) static VERSION: Lazy<String> = Lazy::new(|| {
|
|||||||
crate::dx_build_info::GIT_COMMIT_HASH_SHORT.unwrap_or("was built without git repository")
|
crate::dx_build_info::GIT_COMMIT_HASH_SHORT.unwrap_or("was built without git repository")
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// Cargo's color style
|
||||||
|
/// [source](https://github.com/crate-ci/clap-cargo/blob/master/src/style.rs)
|
||||||
|
pub(crate) const CARGO_STYLING: Styles = Styles::styled()
|
||||||
|
.header(styles::HEADER)
|
||||||
|
.usage(styles::USAGE)
|
||||||
|
.literal(styles::LITERAL)
|
||||||
|
.placeholder(styles::PLACEHOLDER)
|
||||||
|
.error(styles::ERROR)
|
||||||
|
.valid(styles::VALID)
|
||||||
|
.invalid(styles::INVALID);
|
||||||
|
|
||||||
|
pub mod styles {
|
||||||
|
use super::*;
|
||||||
|
pub(crate) const HEADER: Style = AnsiColor::Green.on_default().effects(Effects::BOLD);
|
||||||
|
pub(crate) const USAGE: Style = AnsiColor::Green.on_default().effects(Effects::BOLD);
|
||||||
|
pub(crate) const LITERAL: Style = AnsiColor::Cyan.on_default().effects(Effects::BOLD);
|
||||||
|
pub(crate) const PLACEHOLDER: Style = AnsiColor::Cyan.on_default();
|
||||||
|
pub(crate) const ERROR: Style = AnsiColor::Red.on_default().effects(Effects::BOLD);
|
||||||
|
|
||||||
|
pub(crate) const VALID: Style = AnsiColor::Cyan.on_default().effects(Effects::BOLD);
|
||||||
|
pub(crate) const INVALID: Style = AnsiColor::Yellow.on_default().effects(Effects::BOLD);
|
||||||
|
|
||||||
|
// extra styles for styling logs
|
||||||
|
// we can style stuff using the ansi sequences like: "hotpatched in {GLOW_STYLE}{}{GLOW_STYLE:X}ms"
|
||||||
|
pub(crate) const GLOW_STYLE: Style = AnsiColor::Yellow.on_default();
|
||||||
|
pub(crate) const NOTE_STYLE: Style = AnsiColor::Green.on_default();
|
||||||
|
pub(crate) const LINK_STYLE: Style = AnsiColor::Blue.on_default();
|
||||||
|
}
|
||||||
@@ -106,7 +106,7 @@ impl RunArgs {
|
|||||||
print!("{}", message);
|
print!("{}", message);
|
||||||
}
|
}
|
||||||
BuilderUpdate::BuildFailed { err } => {
|
BuilderUpdate::BuildFailed { err } => {
|
||||||
tracing::error!("Build failed: {:#?}", err);
|
tracing::error!("Build failed: {}", err);
|
||||||
}
|
}
|
||||||
BuilderUpdate::StdoutReceived { msg } => {
|
BuilderUpdate::StdoutReceived { msg } => {
|
||||||
tracing::info!("[{platform}] {msg}");
|
tracing::info!("[{platform}] {msg}");
|
||||||
|
|||||||
@@ -0,0 +1,247 @@
|
|||||||
|
use super::*;
|
||||||
|
use crate::{Result, Workspace};
|
||||||
|
use anyhow::Context;
|
||||||
|
use itertools::Itertools;
|
||||||
|
use self_update::cargo_crate_version;
|
||||||
|
|
||||||
|
/// Run the project with the given arguments
|
||||||
|
///
|
||||||
|
/// This is a shorthand for `dx serve` with interactive mode and hot-reload disabled.
|
||||||
|
#[derive(Clone, Debug, Parser)]
|
||||||
|
pub(crate) struct SelfUpdate {
|
||||||
|
/// Use the latest nightly build.
|
||||||
|
#[clap(long, default_value = "false")]
|
||||||
|
pub nightly: bool,
|
||||||
|
|
||||||
|
/// Specify a version to install.
|
||||||
|
#[clap(long)]
|
||||||
|
pub version: Option<String>,
|
||||||
|
|
||||||
|
/// Install the update.
|
||||||
|
#[clap(long, default_value = "true")]
|
||||||
|
pub install: bool,
|
||||||
|
|
||||||
|
/// List available versions.
|
||||||
|
#[clap(long, default_value = "false")]
|
||||||
|
pub list: bool,
|
||||||
|
|
||||||
|
/// Force the update even if the current version is up to date.
|
||||||
|
#[clap(long, default_value = "false")]
|
||||||
|
pub force: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SelfUpdate {
|
||||||
|
pub async fn self_update(self) -> Result<StructuredOutput> {
|
||||||
|
tokio::task::spawn_blocking(move || {
|
||||||
|
let start = std::time::Instant::now();
|
||||||
|
if self.list {
|
||||||
|
let res = self_update::backends::github::Update::configure()
|
||||||
|
.repo_owner("dioxuslabs")
|
||||||
|
.repo_name("dioxus")
|
||||||
|
.bin_name("dx")
|
||||||
|
.current_version(cargo_crate_version!())
|
||||||
|
.build()
|
||||||
|
.unwrap()
|
||||||
|
.get_latest_releases(cargo_crate_version!())
|
||||||
|
.context("Failed to fetch latest version")?;
|
||||||
|
|
||||||
|
if res.is_empty() {
|
||||||
|
tracing::info!("Your version {} is up to date!", cargo_crate_version!());
|
||||||
|
} else {
|
||||||
|
tracing::info!("Your version {} is out of date!", cargo_crate_version!());
|
||||||
|
tracing::info!(
|
||||||
|
"Available versions: [{}]",
|
||||||
|
res.iter()
|
||||||
|
.map(|r| r.version.clone())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(StructuredOutput::Success);
|
||||||
|
}
|
||||||
|
|
||||||
|
let repo = self_update::backends::github::Update::configure()
|
||||||
|
.repo_owner("dioxuslabs")
|
||||||
|
.repo_name("dioxus")
|
||||||
|
.bin_name("dx")
|
||||||
|
.current_version(cargo_crate_version!())
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let force = self.force || self.version.is_some();
|
||||||
|
let latest = match self.version {
|
||||||
|
Some(version) => repo
|
||||||
|
.get_release_version(&version)
|
||||||
|
.context("Failed to fetch release by tag")?,
|
||||||
|
None => repo
|
||||||
|
.get_latest_release()
|
||||||
|
.context("Failed to fetch latest version")?,
|
||||||
|
};
|
||||||
|
|
||||||
|
if latest.version == cargo_crate_version!() && !force {
|
||||||
|
tracing::info!("Your version {} is up to date!", cargo_crate_version!());
|
||||||
|
return Ok(StructuredOutput::Success);
|
||||||
|
}
|
||||||
|
|
||||||
|
tracing::info!("Your version is out of date!");
|
||||||
|
tracing::info!("- Yours: {}", cargo_crate_version!());
|
||||||
|
tracing::info!("- Latest: {}", latest.version);
|
||||||
|
|
||||||
|
let cur_arch = if cfg!(target_arch = "x86_64") {
|
||||||
|
"x86_64"
|
||||||
|
} else if cfg!(target_arch = "aarch64") {
|
||||||
|
"aarch64"
|
||||||
|
} else {
|
||||||
|
return Err(Error::Unique("Unsupported architecture".to_string()));
|
||||||
|
};
|
||||||
|
|
||||||
|
let cur_os = if cfg!(target_os = "windows") {
|
||||||
|
"windows"
|
||||||
|
} else if cfg!(target_os = "linux") {
|
||||||
|
"linux"
|
||||||
|
} else if cfg!(target_os = "macos") {
|
||||||
|
"darwin"
|
||||||
|
} else {
|
||||||
|
return Err(Error::Unique("Unsupported OS".to_string()));
|
||||||
|
};
|
||||||
|
|
||||||
|
let zip_ext = "zip";
|
||||||
|
|
||||||
|
tracing::debug!("Available assets: {:?}", latest.assets);
|
||||||
|
|
||||||
|
let asset = latest
|
||||||
|
.assets
|
||||||
|
.iter()
|
||||||
|
.find(|a| {
|
||||||
|
a.name.contains(cur_os)
|
||||||
|
&& a.name.contains(cur_arch)
|
||||||
|
&& a.name.ends_with(zip_ext)
|
||||||
|
})
|
||||||
|
.ok_or_else(|| Error::Unique("No suitable release found found".to_string()))?;
|
||||||
|
|
||||||
|
let install_dir = Workspace::dioxus_home_dir().join("self-update");
|
||||||
|
std::fs::create_dir_all(&install_dir).context("Failed to create install directory")?;
|
||||||
|
|
||||||
|
tracing::info!("Downloading update from Github");
|
||||||
|
tracing::debug!("Download URL: {}", asset.download_url);
|
||||||
|
let body = latest.body.unwrap_or_default();
|
||||||
|
let brief = vec![
|
||||||
|
latest.name.to_string(),
|
||||||
|
"".to_string(),
|
||||||
|
latest.date.to_string(),
|
||||||
|
asset.download_url.to_string(),
|
||||||
|
"".to_string(),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.chain(body.lines().map(ToString::to_string).take(7))
|
||||||
|
.chain(std::iter::once(" ...".to_string()))
|
||||||
|
.map(|line| format!(" | {line}"))
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
|
tracing::info!("{}", brief.trim());
|
||||||
|
|
||||||
|
let archive_path = install_dir.join(&asset.name);
|
||||||
|
_ = std::fs::remove_file(&archive_path).ok();
|
||||||
|
let archive_file = std::fs::File::create(&archive_path)?;
|
||||||
|
let download_url = asset.download_url.clone();
|
||||||
|
self_update::Download::from_url(&download_url)
|
||||||
|
.set_header(
|
||||||
|
hyper::http::header::ACCEPT,
|
||||||
|
"application/octet-stream".parse().unwrap(),
|
||||||
|
)
|
||||||
|
.download_to(archive_file)
|
||||||
|
.context("Failed to download update")?;
|
||||||
|
|
||||||
|
let install_dir = install_dir.join("dx");
|
||||||
|
_ = std::fs::remove_dir_all(&install_dir);
|
||||||
|
self_update::Extract::from_source(&archive_path)
|
||||||
|
.extract_into(&install_dir)
|
||||||
|
.context("Failed to extract update")?;
|
||||||
|
|
||||||
|
let executable = install_dir.join("dx");
|
||||||
|
if !executable.exists() {
|
||||||
|
return Err(Error::Unique(format!(
|
||||||
|
"Executable not found in {}",
|
||||||
|
install_dir.display()
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
tracing::info!(
|
||||||
|
"Successfully downloaded update in {}ms! 👍",
|
||||||
|
start.elapsed().as_millis()
|
||||||
|
);
|
||||||
|
|
||||||
|
if self.install {
|
||||||
|
tracing::info!(
|
||||||
|
"Installing dx v{} to {}",
|
||||||
|
latest.version,
|
||||||
|
std::env::current_exe()?.display()
|
||||||
|
);
|
||||||
|
|
||||||
|
if !self.force {
|
||||||
|
tracing::warn!("Continue? (y/n)");
|
||||||
|
print!(" > ");
|
||||||
|
std::io::stdout()
|
||||||
|
.flush()
|
||||||
|
.context("Failed to flush stdout")?;
|
||||||
|
let mut input = String::new();
|
||||||
|
std::io::stdin()
|
||||||
|
.read_line(&mut input)
|
||||||
|
.context("Failed to read input")?;
|
||||||
|
if !input.trim().to_ascii_lowercase().starts_with('y') {
|
||||||
|
tracing::info!("Aborting update");
|
||||||
|
return Ok(StructuredOutput::Success);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self_update::self_replace::self_replace(executable)?;
|
||||||
|
let time_taken = start.elapsed().as_millis();
|
||||||
|
tracing::info!("Done in {} ms! 💫", time_taken)
|
||||||
|
} else {
|
||||||
|
tracing::info!("Update downloaded to {}", install_dir.display());
|
||||||
|
tracing::info!("Run `dx self-update --install` to install the update");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(StructuredOutput::Success)
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.context("Failed to run self-update")?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check against the github release list to see if the currently released `dx` version is
|
||||||
|
/// more up-to-date than our own.
|
||||||
|
///
|
||||||
|
/// We only toss out this warning once and then save to the settings file to ignore this version
|
||||||
|
/// in the future.
|
||||||
|
pub fn log_if_cli_could_update() {
|
||||||
|
tokio::task::spawn_blocking(|| {
|
||||||
|
let release = self_update::backends::github::Update::configure()
|
||||||
|
.repo_owner("dioxuslabs")
|
||||||
|
.repo_name("dioxus")
|
||||||
|
.bin_name("dx")
|
||||||
|
.current_version(cargo_crate_version!())
|
||||||
|
.build()
|
||||||
|
.unwrap()
|
||||||
|
.get_latest_release();
|
||||||
|
|
||||||
|
if let Ok(release) = release {
|
||||||
|
let old = krates::semver::Version::parse(cargo_crate_version!());
|
||||||
|
let new = krates::semver::Version::parse(&release.version);
|
||||||
|
|
||||||
|
if let (Ok(old), Ok(new)) = (old, new) {
|
||||||
|
if old < new {
|
||||||
|
_ = crate::CliSettings::modify_settings(|f| {
|
||||||
|
let ignored = f.ignore_version_update.as_deref().unwrap_or_default();
|
||||||
|
if release.version != ignored {
|
||||||
|
use crate::styles::GLOW_STYLE;
|
||||||
|
tracing::warn!("A new dx version is available: {new}! Run {GLOW_STYLE}dx self-update{GLOW_STYLE:#} to update.");
|
||||||
|
f.ignore_version_update = Some(new.to_string());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -3,11 +3,6 @@ use std::path::PathBuf;
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub(crate) struct ApplicationConfig {
|
pub(crate) struct ApplicationConfig {
|
||||||
pub(crate) asset_dir: Option<PathBuf>,
|
|
||||||
|
|
||||||
#[serde(default)]
|
|
||||||
pub(crate) sub_package: Option<String>,
|
|
||||||
|
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub(crate) out_dir: Option<PathBuf>,
|
pub(crate) out_dir: Option<PathBuf>,
|
||||||
|
|
||||||
@@ -16,4 +11,27 @@ pub(crate) struct ApplicationConfig {
|
|||||||
|
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub(crate) tailwind_output: Option<PathBuf>,
|
pub(crate) tailwind_output: Option<PathBuf>,
|
||||||
|
|
||||||
|
/// Use this file for the info.plist associated with the iOS app.
|
||||||
|
/// `dx` will merge any required settings into this file required to build the app
|
||||||
|
#[serde(default)]
|
||||||
|
pub(crate) ios_info_plist: Option<PathBuf>,
|
||||||
|
|
||||||
|
/// Use this file for the info.plist associated with the macOS app.
|
||||||
|
/// `dx` will merge any required settings into this file required to build the app
|
||||||
|
#[serde(default)]
|
||||||
|
pub(crate) macos_info_plist: Option<PathBuf>,
|
||||||
|
|
||||||
|
/// Use this file for the entitlements.plist associated with the iOS app.
|
||||||
|
#[serde(default)]
|
||||||
|
pub(crate) ios_entitlements: Option<PathBuf>,
|
||||||
|
|
||||||
|
/// Use this file for the entitlements.plist associated with the macOS app.
|
||||||
|
#[serde(default)]
|
||||||
|
pub(crate) macos_entitlements: Option<PathBuf>,
|
||||||
|
|
||||||
|
/// Use this file for the AndroidManifest.xml associated with the Android app.
|
||||||
|
/// `dx` will merge any required settings into this file required to build the app
|
||||||
|
#[serde(default)]
|
||||||
|
pub(crate) android_manifest: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
/// Represents configuration items for the desktop platform.
|
|
||||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
|
||||||
pub(crate) struct DesktopConfig {}
|
|
||||||
@@ -8,9 +8,6 @@ pub(crate) struct DioxusConfig {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub(crate) web: WebConfig,
|
pub(crate) web: WebConfig,
|
||||||
|
|
||||||
#[serde(default)]
|
|
||||||
pub(crate) desktop: DesktopConfig,
|
|
||||||
|
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub(crate) bundle: BundleConfig,
|
pub(crate) bundle: BundleConfig,
|
||||||
}
|
}
|
||||||
@@ -19,11 +16,14 @@ impl Default for DioxusConfig {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
application: ApplicationConfig {
|
application: ApplicationConfig {
|
||||||
asset_dir: None,
|
|
||||||
sub_package: None,
|
|
||||||
out_dir: None,
|
out_dir: None,
|
||||||
tailwind_input: None,
|
tailwind_input: None,
|
||||||
tailwind_output: None,
|
tailwind_output: None,
|
||||||
|
ios_info_plist: None,
|
||||||
|
android_manifest: None,
|
||||||
|
macos_info_plist: None,
|
||||||
|
ios_entitlements: None,
|
||||||
|
macos_entitlements: None,
|
||||||
},
|
},
|
||||||
web: WebConfig {
|
web: WebConfig {
|
||||||
app: WebAppConfig {
|
app: WebAppConfig {
|
||||||
@@ -49,7 +49,6 @@ impl Default for DioxusConfig {
|
|||||||
pre_compress: true,
|
pre_compress: true,
|
||||||
wasm_opt: Default::default(),
|
wasm_opt: Default::default(),
|
||||||
},
|
},
|
||||||
desktop: DesktopConfig::default(),
|
|
||||||
bundle: BundleConfig::default(),
|
bundle: BundleConfig::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
mod app;
|
mod app;
|
||||||
mod bundle;
|
mod bundle;
|
||||||
mod desktop;
|
|
||||||
mod dioxus_config;
|
mod dioxus_config;
|
||||||
mod serve;
|
mod serve;
|
||||||
mod web;
|
mod web;
|
||||||
|
|
||||||
pub(crate) use app::*;
|
pub(crate) use app::*;
|
||||||
pub(crate) use bundle::*;
|
pub(crate) use bundle::*;
|
||||||
pub(crate) use desktop::*;
|
|
||||||
pub(crate) use dioxus_config::*;
|
pub(crate) use dioxus_config::*;
|
||||||
pub(crate) use serve::*;
|
pub(crate) use serve::*;
|
||||||
pub(crate) use web::*;
|
pub(crate) use web::*;
|
||||||
@@ -49,7 +49,6 @@ async fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let args = TraceController::initialize();
|
let args = TraceController::initialize();
|
||||||
|
|
||||||
let result = match args.action {
|
let result = match args.action {
|
||||||
Commands::Translate(opts) => opts.translate(),
|
Commands::Translate(opts) => opts.translate(),
|
||||||
Commands::New(opts) => opts.create(),
|
Commands::New(opts) => opts.create(),
|
||||||
@@ -63,6 +62,7 @@ async fn main() {
|
|||||||
Commands::Bundle(opts) => opts.bundle().await,
|
Commands::Bundle(opts) => opts.bundle().await,
|
||||||
Commands::Run(opts) => opts.run().await,
|
Commands::Run(opts) => opts.run().await,
|
||||||
Commands::BuildAssets(opts) => opts.run().await,
|
Commands::BuildAssets(opts) => opts.run().await,
|
||||||
|
Commands::SelfUpdate(opts) => opts.self_update().await,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Provide a structured output for third party tools that can consume the output of the CLI
|
// Provide a structured output for third party tools that can consume the output of the CLI
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
use crate::{AppBuilder, BuildId, BuildMode, BuilderUpdate, Result, ServeArgs, TraceController};
|
use crate::{
|
||||||
|
styles::{GLOW_STYLE, LINK_STYLE},
|
||||||
|
AppBuilder, BuildId, BuildMode, BuilderUpdate, Result, ServeArgs, TraceController,
|
||||||
|
};
|
||||||
|
|
||||||
mod ansi_buffer;
|
mod ansi_buffer;
|
||||||
mod output;
|
mod output;
|
||||||
@@ -34,26 +37,25 @@ pub(crate) use update::*;
|
|||||||
/// - I want us to be able to detect a `server_fn` in the project and then upgrade from a static server
|
/// - I want us to be able to detect a `server_fn` in the project and then upgrade from a static server
|
||||||
/// to a dynamic one on the fly.
|
/// to a dynamic one on the fly.
|
||||||
pub(crate) async fn serve_all(args: ServeArgs, tracer: &mut TraceController) -> Result<()> {
|
pub(crate) async fn serve_all(args: ServeArgs, tracer: &mut TraceController) -> Result<()> {
|
||||||
// Load the args into a plan, resolving all tooling, build dirs, arguments, decoding the multi-target, etc
|
|
||||||
let mut builder = AppServer::start(args).await?;
|
|
||||||
let mut devserver = WebServer::start(&builder)?;
|
|
||||||
let mut screen = Output::start(builder.interactive).await?;
|
|
||||||
|
|
||||||
// This is our default splash screen. We might want to make this a fancier splash screen in the future
|
// This is our default splash screen. We might want to make this a fancier splash screen in the future
|
||||||
// Also, these commands might not be the most important, but it's all we've got enabled right now
|
// Also, these commands might not be the most important, but it's all we've got enabled right now
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
r#"-----------------------------------------------------------------
|
r#"-----------------------------------------------------------------
|
||||||
Serving your Dioxus app: {} 🚀
|
Serving your Dioxus app! 🚀
|
||||||
• Press `ctrl+c` to exit the server
|
• Press {GLOW_STYLE}`ctrl+c`{GLOW_STYLE:#} to exit the server
|
||||||
• Press `r` to rebuild the app
|
• Press {GLOW_STYLE}`r`{GLOW_STYLE:#} to rebuild the app
|
||||||
• Press `p` to toggle automatic rebuilds
|
• Press {GLOW_STYLE}`p`{GLOW_STYLE:#} to toggle automatic rebuilds
|
||||||
• Press `v` to toggle verbose logging
|
• Press {GLOW_STYLE}`v`{GLOW_STYLE:#} to toggle verbose logging
|
||||||
• Press `/` for more commands and shortcuts
|
• Press {GLOW_STYLE}`/`{GLOW_STYLE:#} for more commands and shortcuts
|
||||||
Learn more at https://dioxuslabs.com/learn/0.6/getting_started
|
Learn more at {LINK_STYLE}https://dioxuslabs.com/learn/0.7/getting_started{LINK_STYLE:#}
|
||||||
----------------------------------------------------------------"#,
|
----------------------------------------------------------------"#,
|
||||||
builder.app_name()
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Load the args into a plan, resolving all tooling, build dirs, arguments, decoding the multi-target, etc
|
||||||
|
let mut builder = AppServer::start(args).await?;
|
||||||
|
let mut devserver = WebServer::start(&builder)?;
|
||||||
|
let mut screen = Output::start(builder.interactive).await?;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// Draw the state of the server to the screen
|
// Draw the state of the server to the screen
|
||||||
screen.render(&builder, &devserver);
|
screen.render(&builder, &devserver);
|
||||||
@@ -89,7 +91,6 @@ pub(crate) async fn serve_all(args: ServeArgs, tracer: &mut TraceController) ->
|
|||||||
// Run the server in the background
|
// Run the server in the background
|
||||||
// Waiting for updates here lets us tap into when clients are added/removed
|
// Waiting for updates here lets us tap into when clients are added/removed
|
||||||
ServeUpdate::NewConnection { id, aslr_reference } => {
|
ServeUpdate::NewConnection { id, aslr_reference } => {
|
||||||
// Send the client
|
|
||||||
devserver
|
devserver
|
||||||
.send_hotreload(builder.applied_hot_reload_changes(BuildId::CLIENT))
|
.send_hotreload(builder.applied_hot_reload_changes(BuildId::CLIENT))
|
||||||
.await;
|
.await;
|
||||||
@@ -128,7 +129,7 @@ pub(crate) async fn serve_all(args: ServeArgs, tracer: &mut TraceController) ->
|
|||||||
screen.push_cargo_log(message);
|
screen.push_cargo_log(message);
|
||||||
}
|
}
|
||||||
BuilderUpdate::BuildFailed { err } => {
|
BuilderUpdate::BuildFailed { err } => {
|
||||||
tracing::error!("Build failed: {:#?}", err);
|
tracing::error!("Build failed: {}", err);
|
||||||
}
|
}
|
||||||
BuilderUpdate::BuildReady { bundle } => match bundle.mode {
|
BuilderUpdate::BuildReady { bundle } => match bundle.mode {
|
||||||
BuildMode::Thin { ref cache, .. } => {
|
BuildMode::Thin { ref cache, .. } => {
|
||||||
@@ -204,7 +205,6 @@ pub(crate) async fn serve_all(args: ServeArgs, tracer: &mut TraceController) ->
|
|||||||
ServeUpdate::Exit { error } => {
|
ServeUpdate::Exit { error } => {
|
||||||
_ = builder.cleanup_all().await;
|
_ = builder.cleanup_all().await;
|
||||||
_ = devserver.shutdown().await;
|
_ = devserver.shutdown().await;
|
||||||
_ = screen.shutdown();
|
|
||||||
|
|
||||||
match error {
|
match error {
|
||||||
Some(err) => return Err(anyhow::anyhow!("{}", err).into()),
|
Some(err) => return Err(anyhow::anyhow!("{}", err).into()),
|
||||||
|
|||||||
@@ -163,13 +163,6 @@ impl Output {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call the shutdown functions that might mess with the terminal settings - see the related code
|
|
||||||
/// in "startup" for more details about what we need to unset
|
|
||||||
pub(crate) fn shutdown(&self) -> io::Result<()> {
|
|
||||||
Self::remote_shutdown(self.interactive)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn remote_shutdown(interactive: bool) -> io::Result<()> {
|
pub(crate) fn remote_shutdown(interactive: bool) -> io::Result<()> {
|
||||||
if interactive {
|
if interactive {
|
||||||
stdout()
|
stdout()
|
||||||
@@ -966,11 +959,23 @@ impl Output {
|
|||||||
" ".repeat(3usize.saturating_sub(log.source.to_string().len()))
|
" ".repeat(3usize.saturating_sub(log.source.to_string().len()))
|
||||||
))
|
))
|
||||||
.style(match log.source {
|
.style(match log.source {
|
||||||
TraceSrc::App(_platform) => Style::new().blue(),
|
TraceSrc::App(_platform) => match log.level {
|
||||||
TraceSrc::Dev => Style::new().magenta(),
|
Level::ERROR => Style::new().red(),
|
||||||
TraceSrc::Build => Style::new().yellow(),
|
Level::WARN => Style::new().yellow(),
|
||||||
TraceSrc::Bundle => Style::new().magenta(),
|
Level::INFO => Style::new().magenta(),
|
||||||
|
Level::DEBUG => Style::new().magenta(),
|
||||||
|
Level::TRACE => Style::new().magenta(),
|
||||||
|
},
|
||||||
|
TraceSrc::Dev => match log.level {
|
||||||
|
Level::ERROR => Style::new().red(),
|
||||||
|
Level::WARN => Style::new().yellow(),
|
||||||
|
Level::INFO => Style::new().blue(),
|
||||||
|
Level::DEBUG => Style::new().blue(),
|
||||||
|
Level::TRACE => Style::new().blue(),
|
||||||
|
},
|
||||||
TraceSrc::Cargo => Style::new().yellow(),
|
TraceSrc::Cargo => Style::new().yellow(),
|
||||||
|
TraceSrc::Build => Style::new().blue(),
|
||||||
|
TraceSrc::Bundle => Style::new().blue(),
|
||||||
TraceSrc::Unknown => Style::new().gray(),
|
TraceSrc::Unknown => Style::new().gray(),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -155,10 +155,12 @@ impl AppServer {
|
|||||||
client.build.package_manifest_dir(),
|
client.build.package_manifest_dir(),
|
||||||
client.build.config.application.tailwind_input.clone(),
|
client.build.config.application.tailwind_input.clone(),
|
||||||
client.build.config.application.tailwind_output.clone(),
|
client.build.config.application.tailwind_output.clone(),
|
||||||
)
|
);
|
||||||
.await?;
|
|
||||||
|
|
||||||
tracing::debug!("Proxied port: {:?}", proxied_port);
|
_ = client.build.start_simulators().await;
|
||||||
|
|
||||||
|
// Encourage the user to update to a new dx version
|
||||||
|
crate::update::log_if_cli_could_update();
|
||||||
|
|
||||||
// Create the runner
|
// Create the runner
|
||||||
let mut runner = Self {
|
let mut runner = Self {
|
||||||
@@ -446,7 +448,13 @@ impl AppServer {
|
|||||||
// Also make sure the builder isn't busy since that might cause issues with hotreloads
|
// Also make sure the builder isn't busy since that might cause issues with hotreloads
|
||||||
// https://github.com/DioxusLabs/dioxus/issues/3361
|
// https://github.com/DioxusLabs/dioxus/issues/3361
|
||||||
if !msg.is_empty() && self.client.can_receive_hotreloads() {
|
if !msg.is_empty() && self.client.can_receive_hotreloads() {
|
||||||
tracing::info!(dx_src = ?TraceSrc::Dev, "Hotreloading: {}", file);
|
use crate::styles::NOTE_STYLE;
|
||||||
|
tracing::info!(dx_src = ?TraceSrc::Dev, "Hotreloading: {NOTE_STYLE}{}{NOTE_STYLE:#}", file);
|
||||||
|
|
||||||
|
if !server.has_hotreload_sockets() && self.client.build.platform != Platform::Web {
|
||||||
|
tracing::warn!("No clients to hotreload - try reloading the app!");
|
||||||
|
}
|
||||||
|
|
||||||
server.send_hotreload(msg).await;
|
server.send_hotreload(msg).await;
|
||||||
} else {
|
} else {
|
||||||
tracing::debug!(dx_src = ?TraceSrc::Dev, "Ignoring file change: {}", file);
|
tracing::debug!(dx_src = ?TraceSrc::Dev, "Ignoring file change: {}", file);
|
||||||
@@ -473,6 +481,8 @@ impl AppServer {
|
|||||||
let should_open = self.client.stage == BuildStage::Success
|
let should_open = self.client.stage == BuildStage::Success
|
||||||
&& (self.server.as_ref().map(|s| s.stage == BuildStage::Success)).unwrap_or(true);
|
&& (self.server.as_ref().map(|s| s.stage == BuildStage::Success)).unwrap_or(true);
|
||||||
|
|
||||||
|
use crate::cli::styles::GLOW_STYLE;
|
||||||
|
|
||||||
if should_open {
|
if should_open {
|
||||||
let time_taken = artifacts
|
let time_taken = artifacts
|
||||||
.time_end
|
.time_end
|
||||||
@@ -481,11 +491,14 @@ impl AppServer {
|
|||||||
|
|
||||||
if self.client.builds_opened == 0 {
|
if self.client.builds_opened == 0 {
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
"Build completed successfully in {:?}ms, launching app! 💫",
|
"Build completed successfully in {GLOW_STYLE}{:?}ms{GLOW_STYLE:#}, launching app! 💫",
|
||||||
time_taken.as_millis()
|
time_taken.as_millis()
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
tracing::info!("Build completed in {:?}ms", time_taken.as_millis());
|
tracing::info!(
|
||||||
|
"Build completed in {GLOW_STYLE}{:?}ms{GLOW_STYLE:#}",
|
||||||
|
time_taken.as_millis()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let open_browser = self.client.builds_opened == 0 && self.open_browser;
|
let open_browser = self.client.builds_opened == 0 && self.open_browser;
|
||||||
|
|||||||
@@ -264,6 +264,10 @@ impl WebServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn has_hotreload_sockets(&self) -> bool {
|
||||||
|
!self.hot_reload_sockets.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
/// Sends hot reloadable changes to all clients.
|
/// Sends hot reloadable changes to all clients.
|
||||||
pub(crate) async fn send_hotreload(&mut self, reload: HotReloadMsg) {
|
pub(crate) async fn send_hotreload(&mut self, reload: HotReloadMsg) {
|
||||||
if reload.is_empty() {
|
if reload.is_empty() {
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ pub(crate) struct CliSettings {
|
|||||||
pub(crate) wsl_file_poll_interval: Option<u16>,
|
pub(crate) wsl_file_poll_interval: Option<u16>,
|
||||||
/// Use tooling from path rather than downloading them.
|
/// Use tooling from path rather than downloading them.
|
||||||
pub(crate) no_downloads: Option<bool>,
|
pub(crate) no_downloads: Option<bool>,
|
||||||
|
/// Ignore updates for this version
|
||||||
|
pub(crate) ignore_version_update: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CliSettings {
|
impl CliSettings {
|
||||||
|
|||||||
@@ -19,12 +19,12 @@ impl TailwindCli {
|
|||||||
Self { version }
|
Self { version }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn serve(
|
pub(crate) fn serve(
|
||||||
manifest_dir: PathBuf,
|
manifest_dir: PathBuf,
|
||||||
input_path: Option<PathBuf>,
|
input_path: Option<PathBuf>,
|
||||||
output_path: Option<PathBuf>,
|
output_path: Option<PathBuf>,
|
||||||
) -> Result<tokio::task::JoinHandle<Result<()>>> {
|
) -> tokio::task::JoinHandle<Result<()>> {
|
||||||
Ok(tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let Some(tailwind) = Self::autodetect(&manifest_dir) else {
|
let Some(tailwind) = Self::autodetect(&manifest_dir) else {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
@@ -38,12 +38,16 @@ impl TailwindCli {
|
|||||||
proc.wait_with_output().await?;
|
proc.wait_with_output().await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}))
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Use the correct tailwind version based on the manifest directory.
|
/// Use the correct tailwind version based on the manifest directory.
|
||||||
|
///
|
||||||
/// - If `tailwind.config.js` or `tailwind.config.ts` exists, use v3.
|
/// - If `tailwind.config.js` or `tailwind.config.ts` exists, use v3.
|
||||||
/// - If `tailwind.css` exists, use v4.
|
/// - If `tailwind.css` exists, use v4.
|
||||||
|
///
|
||||||
|
/// Note that v3 still uses the tailwind.css file, but usually the accompanying js file indicates
|
||||||
|
/// that the project is using v3.
|
||||||
pub(crate) fn autodetect(manifest_dir: &Path) -> Option<Self> {
|
pub(crate) fn autodetect(manifest_dir: &Path) -> Option<Self> {
|
||||||
if manifest_dir.join("tailwind.config.js").exists() {
|
if manifest_dir.join("tailwind.config.js").exists() {
|
||||||
return Some(Self::v3());
|
return Some(Self::v3());
|
||||||
@@ -92,8 +96,9 @@ impl TailwindCli {
|
|||||||
.arg("--output")
|
.arg("--output")
|
||||||
.arg(output_path)
|
.arg(output_path)
|
||||||
.arg("--watch")
|
.arg("--watch")
|
||||||
.stdout(Stdio::piped())
|
.stdin(Stdio::null())
|
||||||
.stderr(Stdio::piped())
|
.stdout(Stdio::null())
|
||||||
|
.stderr(Stdio::null())
|
||||||
.spawn()?;
|
.spawn()?;
|
||||||
|
|
||||||
Ok(proc)
|
Ok(proc)
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ impl WasmBindgen {
|
|||||||
.expect("input_path should be valid utf8");
|
.expect("input_path should be valid utf8");
|
||||||
args.push(input_path);
|
args.push(input_path);
|
||||||
|
|
||||||
tracing::debug!("wasm-bindgen args: {:#?}", args);
|
tracing::debug!("wasm-bindgen: {:#?}", args);
|
||||||
|
|
||||||
// Run bindgen
|
// Run bindgen
|
||||||
let output = Command::new(binary).args(args).output().await?;
|
let output = Command::new(binary).args(args).output().await?;
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ use crate::Result;
|
|||||||
use crate::{config::DioxusConfig, AndroidTools};
|
use crate::{config::DioxusConfig, AndroidTools};
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use ignore::gitignore::Gitignore;
|
use ignore::gitignore::Gitignore;
|
||||||
use krates::KrateDetails;
|
use krates::{semver::Version, KrateDetails, LockOptions};
|
||||||
use krates::{Cmd, Krates, NodeId};
|
use krates::{Cmd, Krates, NodeId};
|
||||||
use std::path::Path;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::{collections::HashSet, path::Path};
|
||||||
use target_lexicon::Triple;
|
use target_lexicon::Triple;
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
|
|
||||||
@@ -34,9 +34,12 @@ impl Workspace {
|
|||||||
return Ok(ws.clone());
|
return Ok(ws.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
tracing::debug!("Loading workspace!");
|
let mut cmd = Cmd::new();
|
||||||
|
cmd.lock_opts(LockOptions {
|
||||||
let cmd = Cmd::new();
|
offline: true,
|
||||||
|
frozen: false,
|
||||||
|
locked: false,
|
||||||
|
});
|
||||||
let mut builder = krates::Builder::new();
|
let mut builder = krates::Builder::new();
|
||||||
builder.workspace(true);
|
builder.workspace(true);
|
||||||
let krates = builder
|
let krates = builder
|
||||||
@@ -79,6 +82,23 @@ impl Workspace {
|
|||||||
android_tools,
|
android_tools,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
tracing::debug!(
|
||||||
|
r#"Initialized workspace:
|
||||||
|
• sysroot: {sysroot}
|
||||||
|
• rustc version: {rustc_version}
|
||||||
|
• workspace root: {workspace_root}
|
||||||
|
• dioxus versions: [{dioxus_versions:?}]"#,
|
||||||
|
sysroot = workspace.sysroot.display(),
|
||||||
|
rustc_version = workspace.rustc_version,
|
||||||
|
workspace_root = workspace.workspace_root().display(),
|
||||||
|
dioxus_versions = workspace
|
||||||
|
.dioxus_versions()
|
||||||
|
.iter()
|
||||||
|
.map(|v| v.to_string())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ")
|
||||||
|
);
|
||||||
|
|
||||||
lock.replace(workspace.clone());
|
lock.replace(workspace.clone());
|
||||||
|
|
||||||
Ok(workspace)
|
Ok(workspace)
|
||||||
@@ -116,6 +136,50 @@ impl Workspace {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn check_dioxus_version_against_cli(&self) {
|
||||||
|
let dx_semver = Version::parse(env!("CARGO_PKG_VERSION")).unwrap();
|
||||||
|
let dioxus_versions = self.dioxus_versions();
|
||||||
|
|
||||||
|
tracing::trace!("dx version: {}", dx_semver);
|
||||||
|
tracing::trace!("dioxus versions: {:?}", dioxus_versions);
|
||||||
|
|
||||||
|
// if there are no dioxus versions in the workspace, we don't need to check anything
|
||||||
|
// dx is meant to be compatible with non-dioxus projects too.
|
||||||
|
if dioxus_versions.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let min = dioxus_versions.iter().min().unwrap();
|
||||||
|
let max = dioxus_versions.iter().max().unwrap();
|
||||||
|
|
||||||
|
// If the minimum dioxus version is greater than the current cli version, warn the user
|
||||||
|
if min > &dx_semver || max < &dx_semver {
|
||||||
|
tracing::error!(
|
||||||
|
r#"🚫dx and dioxus versions are incompatible!
|
||||||
|
• dx version: {dx_semver}
|
||||||
|
• dioxus versions: [{}]"#,
|
||||||
|
dioxus_versions
|
||||||
|
.iter()
|
||||||
|
.map(|v| v.to_string())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get all the versions of dioxus in the workspace
|
||||||
|
pub fn dioxus_versions(&self) -> Vec<Version> {
|
||||||
|
let mut versions = HashSet::new();
|
||||||
|
for krate in self.krates.krates() {
|
||||||
|
if krate.name == "dioxus" {
|
||||||
|
versions.insert(krate.version.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut versions = versions.into_iter().collect::<Vec<_>>();
|
||||||
|
versions.sort();
|
||||||
|
versions
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub fn rust_lld(&self) -> PathBuf {
|
pub fn rust_lld(&self) -> PathBuf {
|
||||||
self.sysroot
|
self.sysroot
|
||||||
|
|||||||
@@ -98,7 +98,6 @@ impl ComponentBody {
|
|||||||
|
|
||||||
let Generics { where_clause, .. } = generics;
|
let Generics { where_clause, .. } = generics;
|
||||||
let (_, impl_generics, _) = generics.split_for_impl();
|
let (_, impl_generics, _) = generics.split_for_impl();
|
||||||
let generics_turbofish = impl_generics.as_turbofish();
|
|
||||||
|
|
||||||
// We generate a struct with the same name as the component but called `Props`
|
// We generate a struct with the same name as the component but called `Props`
|
||||||
let struct_ident = Ident::new(&format!("{fn_ident}Props"), fn_ident.span());
|
let struct_ident = Ident::new(&format!("{fn_ident}Props"), fn_ident.span());
|
||||||
@@ -147,8 +146,6 @@ impl ComponentBody {
|
|||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#vis fn #fn_ident #generics (#emit_props) #fn_output #where_clause {
|
#vis fn #fn_ident #generics (#emit_props) #fn_output #where_clause {
|
||||||
{
|
{
|
||||||
// In debug mode we can detect if the user is calling the component like a function
|
|
||||||
dioxus_core::internal::verify_component_called_as_component(#fn_ident #generics_turbofish);
|
|
||||||
#body
|
#body
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,8 +33,6 @@ mod hotreload_utils;
|
|||||||
/// Items exported from this module are used in macros and should not be used directly.
|
/// Items exported from this module are used in macros and should not be used directly.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub mod internal {
|
pub mod internal {
|
||||||
pub use crate::properties::verify_component_called_as_component;
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub use crate::hotreload_utils::{
|
pub use crate::hotreload_utils::{
|
||||||
DynamicLiteralPool, DynamicValuePool, FmtSegment, FmtedSegments, HotReloadAttributeValue,
|
DynamicLiteralPool, DynamicValuePool, FmtSegment, FmtedSegments, HotReloadAttributeValue,
|
||||||
|
|||||||
@@ -114,35 +114,6 @@ where
|
|||||||
P::builder()
|
P::builder()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A warning that will trigger if a component is called as a function
|
|
||||||
#[warnings::warning]
|
|
||||||
pub(crate) fn component_called_as_function<C: ComponentFunction<P, M>, P, M>(_: C) {
|
|
||||||
// We trim WithOwner from the end of the type name for component with a builder that include a special owner which may not match the function name directly
|
|
||||||
let type_name = std::any::type_name::<C>();
|
|
||||||
let component_name = Runtime::with(|rt| {
|
|
||||||
current_scope_id()
|
|
||||||
.ok()
|
|
||||||
.and_then(|id| rt.get_state(id).map(|scope| scope.name))
|
|
||||||
})
|
|
||||||
.ok()
|
|
||||||
.flatten();
|
|
||||||
|
|
||||||
// If we are in a component, and the type name is the same as the active component name, then we can just return
|
|
||||||
if component_name == Some(type_name) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise the component was called like a function, so we should log an error
|
|
||||||
tracing::error!("It looks like you called the component {type_name} like a function instead of a component. Components should be called with braces like `{type_name} {{ prop: value }}` instead of as a function");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Make sure that this component is currently running as a component, not a function call
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[allow(clippy::no_effect)]
|
|
||||||
pub fn verify_component_called_as_component<C: ComponentFunction<P, M>, P, M>(component: C) {
|
|
||||||
component_called_as_function(component);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Any component that implements the `ComponentFn` trait can be used as a component.
|
/// Any component that implements the `ComponentFn` trait can be used as a component.
|
||||||
///
|
///
|
||||||
/// This trait is automatically implemented for functions that are in one of the following forms:
|
/// This trait is automatically implemented for functions that are in one of the following forms:
|
||||||
|
|||||||
@@ -239,14 +239,7 @@ impl VirtualDom {
|
|||||||
///
|
///
|
||||||
/// Note: the VirtualDom is not progressed, you must either "run_with_deadline" or use "rebuild" to progress it.
|
/// Note: the VirtualDom is not progressed, you must either "run_with_deadline" or use "rebuild" to progress it.
|
||||||
pub fn new(app: fn() -> Element) -> Self {
|
pub fn new(app: fn() -> Element) -> Self {
|
||||||
Self::new_with_props(
|
Self::new_with_props(app, ())
|
||||||
move || {
|
|
||||||
use warnings::Warning;
|
|
||||||
// The root props don't come from a vcomponent so we need to manually rerun them sometimes
|
|
||||||
crate::properties::component_called_as_function::allow(app)
|
|
||||||
},
|
|
||||||
(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new VirtualDom with the given properties for the root component.
|
/// Create a new VirtualDom with the given properties for the root component.
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ tao = { workspace = true, features = ["rwh_05"] }
|
|||||||
once_cell = { workspace = true }
|
once_cell = { workspace = true }
|
||||||
dioxus-history = { workspace = true }
|
dioxus-history = { workspace = true }
|
||||||
base64 = { workspace = true }
|
base64 = { workspace = true }
|
||||||
|
libc = "0.2.170"
|
||||||
|
|
||||||
[target.'cfg(unix)'.dependencies]
|
[target.'cfg(unix)'.dependencies]
|
||||||
signal-hook = "0.3.17"
|
signal-hook = "0.3.17"
|
||||||
|
|||||||
+91
-13
@@ -7,7 +7,8 @@ use crate::{
|
|||||||
shortcut::ShortcutRegistry,
|
shortcut::ShortcutRegistry,
|
||||||
webview::WebviewInstance,
|
webview::WebviewInstance,
|
||||||
};
|
};
|
||||||
use dioxus_core::{ElementId, VirtualDom};
|
use dioxus_core::{ElementId, ScopeId, VirtualDom};
|
||||||
|
use dioxus_history::History;
|
||||||
use dioxus_html::PlatformEventData;
|
use dioxus_html::PlatformEventData;
|
||||||
use std::{
|
use std::{
|
||||||
any::Any,
|
any::Any,
|
||||||
@@ -15,6 +16,7 @@ use std::{
|
|||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
|
time::Duration,
|
||||||
};
|
};
|
||||||
use tao::{
|
use tao::{
|
||||||
dpi::PhysicalSize,
|
dpi::PhysicalSize,
|
||||||
@@ -168,12 +170,10 @@ impl App {
|
|||||||
|
|
||||||
#[cfg(all(feature = "devtools", debug_assertions))]
|
#[cfg(all(feature = "devtools", debug_assertions))]
|
||||||
pub fn connect_hotreload(&self) {
|
pub fn connect_hotreload(&self) {
|
||||||
if let Some(endpoint) = dioxus_cli_config::devserver_ws_endpoint() {
|
let proxy = self.shared.proxy.clone();
|
||||||
let proxy = self.shared.proxy.clone();
|
dioxus_devtools::connect(move |msg| {
|
||||||
dioxus_devtools::connect(endpoint, move |msg| {
|
_ = proxy.send_event(UserWindowEvent::HotReloadEvent(msg));
|
||||||
_ = proxy.send_event(UserWindowEvent::HotReloadEvent(msg));
|
})
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_new_window(&mut self) {
|
pub fn handle_new_window(&mut self) {
|
||||||
@@ -322,8 +322,14 @@ impl App {
|
|||||||
|
|
||||||
#[cfg(all(feature = "devtools", debug_assertions))]
|
#[cfg(all(feature = "devtools", debug_assertions))]
|
||||||
pub fn handle_hot_reload_msg(&mut self, msg: dioxus_devtools::DevserverMsg) {
|
pub fn handle_hot_reload_msg(&mut self, msg: dioxus_devtools::DevserverMsg) {
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
use dioxus_devtools::DevserverMsg;
|
use dioxus_devtools::DevserverMsg;
|
||||||
|
|
||||||
|
// Amount of time that toats should be displayed.
|
||||||
|
const TOAST_TIMEOUT: Duration = Duration::from_secs(2);
|
||||||
|
const TOAST_TIMEOUT_LONG: Duration = Duration::from_secs(3600); // Duration::MAX is too long for JS.
|
||||||
|
|
||||||
match msg {
|
match msg {
|
||||||
DevserverMsg::HotReload(hr_msg) => {
|
DevserverMsg::HotReload(hr_msg) => {
|
||||||
for webview in self.webviews.values_mut() {
|
for webview in self.webviews.values_mut() {
|
||||||
@@ -343,13 +349,49 @@ impl App {
|
|||||||
webview.kick_stylsheets();
|
webview.kick_stylsheets();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if hr_msg.jump_table.is_some()
|
||||||
|
&& hr_msg.for_build_id == Some(dioxus_cli_config::build_id())
|
||||||
|
{
|
||||||
|
self.send_toast_to_all(
|
||||||
|
"Hot-patch success!",
|
||||||
|
&format!("App successfully patched in {} ms", hr_msg.ms_elapsed),
|
||||||
|
"success",
|
||||||
|
TOAST_TIMEOUT,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
DevserverMsg::FullReloadCommand
|
DevserverMsg::FullReloadCommand => {
|
||||||
| DevserverMsg::FullReloadStart
|
self.send_toast_to_all(
|
||||||
| DevserverMsg::FullReloadFailed => {
|
"Successfully rebuilt.",
|
||||||
// usually only web gets this message - what are we supposed to do?
|
"Your app was rebuilt successfully and without error.",
|
||||||
// Maybe we could just binary patch ourselves in place without losing window state?
|
"success",
|
||||||
|
TOAST_TIMEOUT,
|
||||||
|
true,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
DevserverMsg::FullReloadStart => self.send_toast_to_all(
|
||||||
|
"Your app is being rebuilt.",
|
||||||
|
"A non-hot-reloadable change occurred and we must rebuild.",
|
||||||
|
"info",
|
||||||
|
TOAST_TIMEOUT_LONG,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
DevserverMsg::FullReloadFailed => self.send_toast_to_all(
|
||||||
|
"Oops! The build failed.",
|
||||||
|
"We tried to rebuild your app, but something went wrong.",
|
||||||
|
"error",
|
||||||
|
TOAST_TIMEOUT_LONG,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
DevserverMsg::HotPatchStart => self.send_toast_to_all(
|
||||||
|
"Hot-patching app...",
|
||||||
|
"Hot-patching modified Rust code.",
|
||||||
|
"info",
|
||||||
|
TOAST_TIMEOUT_LONG,
|
||||||
|
false,
|
||||||
|
),
|
||||||
DevserverMsg::Shutdown => {
|
DevserverMsg::Shutdown => {
|
||||||
self.control_flow = ControlFlow::Exit;
|
self.control_flow = ControlFlow::Exit;
|
||||||
}
|
}
|
||||||
@@ -357,6 +399,20 @@ impl App {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "devtools", debug_assertions))]
|
||||||
|
fn send_toast_to_all(
|
||||||
|
&self,
|
||||||
|
header_text: &str,
|
||||||
|
message: &str,
|
||||||
|
level: &str,
|
||||||
|
duration: Duration,
|
||||||
|
after_reload: bool,
|
||||||
|
) {
|
||||||
|
for webview in self.webviews.values() {
|
||||||
|
webview.show_toast(header_text, message, level, duration, after_reload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn handle_file_dialog_msg(&mut self, msg: IpcMessage, window: WindowId) {
|
pub fn handle_file_dialog_msg(&mut self, msg: IpcMessage, window: WindowId) {
|
||||||
let Ok(file_dialog) = serde_json::from_value::<FileDialogRequest>(msg.params()) else {
|
let Ok(file_dialog) = serde_json::from_value::<FileDialogRequest>(msg.params()) else {
|
||||||
return;
|
return;
|
||||||
@@ -462,6 +518,9 @@ impl App {
|
|||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
fn persist_window_state(&self) {
|
fn persist_window_state(&self) {
|
||||||
|
use dioxus_core::ScopeId;
|
||||||
|
use dioxus_history::History;
|
||||||
|
|
||||||
if let Some(webview) = self.webviews.values().next() {
|
if let Some(webview) = self.webviews.values().next() {
|
||||||
let window = &webview.desktop_context.window;
|
let window = &webview.desktop_context.window;
|
||||||
|
|
||||||
@@ -491,12 +550,20 @@ impl App {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let url = webview.dom.in_runtime(|| {
|
||||||
|
ScopeId::ROOT
|
||||||
|
.consume_context::<Rc<dyn History>>()
|
||||||
|
.unwrap()
|
||||||
|
.current_route()
|
||||||
|
});
|
||||||
|
|
||||||
let state = PreservedWindowState {
|
let state = PreservedWindowState {
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
width: size.width.max(200),
|
width: size.width.max(200),
|
||||||
height: size.height.saturating_sub(adjustment).max(200),
|
height: size.height.saturating_sub(adjustment).max(200),
|
||||||
monitor: monitor_name.to_string(),
|
monitor: monitor_name.to_string(),
|
||||||
|
url: Some(url),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Yes... I know... we're loading a file that might not be ours... but it's a debug feature
|
// Yes... I know... we're loading a file that might not be ours... but it's a debug feature
|
||||||
@@ -540,6 +607,16 @@ impl App {
|
|||||||
if explicit_inner_size.is_none() {
|
if explicit_inner_size.is_none() {
|
||||||
window.set_inner_size(tao::dpi::PhysicalSize::new(size.0, size.1));
|
window.set_inner_size(tao::dpi::PhysicalSize::new(size.0, size.1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the url if it exists
|
||||||
|
webview.dom.in_runtime(|| {
|
||||||
|
if let Some(url) = state.url {
|
||||||
|
ScopeId::ROOT
|
||||||
|
.consume_context::<Rc<dyn History>>()
|
||||||
|
.unwrap()
|
||||||
|
.replace(url);
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -563,7 +640,7 @@ impl App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// give it a moment for the event to be processed
|
// give it a moment for the event to be processed
|
||||||
std::thread::sleep(std::time::Duration::from_secs(1));
|
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -578,6 +655,7 @@ struct PreservedWindowState {
|
|||||||
width: u32,
|
width: u32,
|
||||||
height: u32,
|
height: u32,
|
||||||
monitor: String,
|
monitor: String,
|
||||||
|
url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Hide the last window when using LastWindowHides.
|
/// Hide the last window when using LastWindowHides.
|
||||||
|
|||||||
@@ -0,0 +1,184 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Dioxus app</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||||
|
<style>
|
||||||
|
/* Inter Font */
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap');
|
||||||
|
|
||||||
|
#dx-toast-template {
|
||||||
|
display: none;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dx-toast {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
right: 0;
|
||||||
|
padding-right: 10px;
|
||||||
|
user-select: none;
|
||||||
|
/* transition: transform 0.2s ease; */
|
||||||
|
z-index: 2147483647;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dx-toast .dx-toast-inner {
|
||||||
|
/* transition: right 0.2s ease-out; */
|
||||||
|
position: fixed;
|
||||||
|
|
||||||
|
background-color: #181B20;
|
||||||
|
color: #ffffff;
|
||||||
|
font-family: "Inter", sans-serif;
|
||||||
|
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto auto;
|
||||||
|
max-width: 400px;
|
||||||
|
min-height: 56px;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dx-toast .dx-toast-inner {
|
||||||
|
cursor: pointer;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dx-toast .dx-toast-level-bar-container {
|
||||||
|
height: 100%;
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dx-toast .dx-toast-level-bar-container .dx-toast-level-bar {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 5px 0px 0px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dx-toast .dx-toast-content {
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dx-toast .dx-toast-header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: start;
|
||||||
|
align-items: end;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dx-toast .dx-toast-header>svg {
|
||||||
|
height: 18px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dx-toast .dx-toast-header .dx-toast-header-text {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dx-toast .dx-toast-msg {
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 400;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dx-toast-level-bar.info {
|
||||||
|
background-color: #428EFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dx-toast-level-bar.success {
|
||||||
|
background-color: #42FF65;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dx-toast-level-bar.error {
|
||||||
|
background-color: #FF4242;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
const STORAGE_KEY = "SCHEDULED-DX-TOAST";
|
||||||
|
let currentTimeout = null;
|
||||||
|
let currentToastId = 0;
|
||||||
|
|
||||||
|
// Show a toast, removing the previous one.
|
||||||
|
function showDXToast(headerText, message, progressLevel, durationMs) {
|
||||||
|
document.getElementById("__dx-toast-decor").className = `dx-toast-level-bar ${progressLevel}`;
|
||||||
|
document.getElementById("__dx-toast-text").innerText = headerText;
|
||||||
|
document.getElementById("__dx-toast-msg").innerText = message;
|
||||||
|
document.getElementById("__dx-toast-inner").style.right = "0";
|
||||||
|
document.getElementById("__dx-toast").addEventListener("click", closeDXToast);
|
||||||
|
|
||||||
|
|
||||||
|
// Wait a bit of time so animation plays correctly.
|
||||||
|
setTimeout(
|
||||||
|
() => {
|
||||||
|
let ourToastId = currentToastId;
|
||||||
|
currentTimeout = setTimeout(() => {
|
||||||
|
if (ourToastId == currentToastId) {
|
||||||
|
closeDXToast();
|
||||||
|
}
|
||||||
|
}, durationMs);
|
||||||
|
},
|
||||||
|
100
|
||||||
|
);
|
||||||
|
|
||||||
|
currentToastId += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Schedule a toast to be displayed after reload.
|
||||||
|
function scheduleDXToast(headerText, message, level, durationMs) {
|
||||||
|
let data = {
|
||||||
|
headerText,
|
||||||
|
message,
|
||||||
|
level,
|
||||||
|
durationMs,
|
||||||
|
};
|
||||||
|
|
||||||
|
let jsonData = JSON.stringify(data);
|
||||||
|
sessionStorage.setItem(STORAGE_KEY, jsonData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the current toast.
|
||||||
|
function closeDXToast() {
|
||||||
|
document.getElementById("__dx-toast-inner").style.right = "-1000px";
|
||||||
|
clearTimeout(currentTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle any scheduled toasts after reload.
|
||||||
|
let potentialData = sessionStorage.getItem(STORAGE_KEY);
|
||||||
|
if (potentialData) {
|
||||||
|
sessionStorage.removeItem(STORAGE_KEY);
|
||||||
|
let data = JSON.parse(potentialData);
|
||||||
|
showDXToast(data.headerText, data.message, data.level, data.durationMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.scheduleDXToast = scheduleDXToast;
|
||||||
|
window.showDXToast = showDXToast;
|
||||||
|
window.closeDXToast = closeDXToast;
|
||||||
|
</script>
|
||||||
|
<!-- CUSTOM HEAD -->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="__dx-toast" class="dx-toast">
|
||||||
|
<div id="__dx-toast-inner" class="dx-toast-inner" style="right:-1000px;">
|
||||||
|
<div class="dx-toast-level-bar-container">
|
||||||
|
<div id="__dx-toast-decor" class="dx-toast-level-bar __info"></div>
|
||||||
|
</div>
|
||||||
|
<div class="dx-toast-content">
|
||||||
|
<div class="dx-toast-header">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" preserveAspectRatio="none">
|
||||||
|
<path d="M22.158 1.783c0 3.077-.851 5.482-2.215 7.377s-3.32 3.557-5.447 5.33-4.425 3.657-6.252 6.195-3.102 5.515-3.102 9.532h4.699c0-3.077.853-5.377 2.217-7.272s3.32-3.557 5.447-5.33 4.425-3.657 6.252-6.195 3.102-5.62 3.102-9.637z" fill="#e96020"/>
|
||||||
|
<path d="M9.531 25.927c-.635 0-1.021.515-1.02 1.15s.385 1.151 1.02 1.15H22.47a1.151 1.151 0 1 0 0-2.301zm1.361-4.076c-.608 0-.954.558-.953 1.166s.346 1.035.953 1.035h10.217a1.101 1.101 0 1 0 0-2.201zm0-13.594a1.101 1.101 0 1 0 0 2.201h10.217c.607 0 .953-.598.953-1.205s-.345-.996-.953-.996zM9.531 4.021A1.15 1.15 0 0 0 8.38 5.17a1.15 1.15 0 0 0 1.15 1.15h12.94c.635 0 1.021-.498 1.02-1.133s-.386-1.166-1.02-1.166z" fill="#2d323b"/>
|
||||||
|
<path d="M5.142 1.783c0 4.016 1.275 7.099 3.102 9.637s4.125 4.422 6.252 6.195 4.083 3.656 5.447 5.551 2.215 3.974 2.215 7.051h4.701c0-4.016-1.275-7.038-3.102-9.576s-4.125-4.422-6.252-6.195-4.083-3.435-5.447-5.33S9.841 4.86 9.841 1.783z" fill="#00a8d6"/>
|
||||||
|
</svg>
|
||||||
|
<h3 id="__dx-toast-text" class="dx-toast-header-text">Your app is being rebuilt.</h3>
|
||||||
|
</div>
|
||||||
|
<p id="__dx-toast-msg" class="dx-toast-msg">A non-hot-reloadable change occurred and we must rebuild.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="main"></div>
|
||||||
|
<!-- MODULE LOADER -->
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
File renamed without changes.
+105
-34
@@ -8,6 +8,52 @@ use dioxus_document::eval;
|
|||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use tao::event::{Event, StartCause, WindowEvent};
|
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<dyn Fn() -> Box<dyn Any> + Send + Sync>>,
|
||||||
|
platform_config: Vec<Box<dyn Any>>,
|
||||||
|
) {
|
||||||
|
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::<Config>().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.
|
/// 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
|
/// 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.
|
/// Expose the `Java_dev_dioxus_main_WryActivity_create` function to the JNI layer.
|
||||||
pub fn launch_virtual_dom(virtual_dom: VirtualDom, desktop_config: Config) -> ! {
|
/// We hardcode these to have a single trampoline for host Java code to call into.
|
||||||
#[cfg(feature = "tokio_runtime")]
|
///
|
||||||
{
|
/// This saves us from having to plumb the top-level package name all the way down into
|
||||||
tokio::runtime::Builder::new_multi_thread()
|
/// this file. This is better for modularity (ie just call dioxus' main to run the app) as
|
||||||
.enable_all()
|
/// well as cache thrashing since this crate doesn't rely on external env vars.
|
||||||
.build()
|
///
|
||||||
.unwrap()
|
/// The CLI is expecting to find `dev.dioxus.main` in the final library. If you find a need to
|
||||||
.block_on(tokio::task::unconstrained(async move {
|
/// change this, you'll need to change the CLI as well.
|
||||||
launch_virtual_dom_blocking(virtual_dom, desktop_config)
|
#[cfg(target_os = "android")]
|
||||||
}));
|
#[no_mangle]
|
||||||
|
#[inline(never)]
|
||||||
unreachable!("The desktop launch function will never exit")
|
pub extern "C" fn start_app() {
|
||||||
}
|
wry::android_binding!(dev_dioxus, main, wry);
|
||||||
|
tao::android_binding!(
|
||||||
#[cfg(not(feature = "tokio_runtime"))]
|
dev_dioxus,
|
||||||
{
|
main,
|
||||||
launch_virtual_dom_blocking(virtual_dom, desktop_config);
|
WryActivity,
|
||||||
}
|
wry::android_setup,
|
||||||
|
dioxus_main_root_fn,
|
||||||
|
tao
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Launches the WebView and runs the event loop, with configuration and root props.
|
#[cfg(target_os = "android")]
|
||||||
pub fn launch(
|
#[doc(hidden)]
|
||||||
root: fn() -> Element,
|
pub fn dioxus_main_root_fn() {
|
||||||
contexts: Vec<Box<dyn Fn() -> Box<dyn Any> + Send + Sync>>,
|
// we're going to find the `main` symbol using dlsym directly and call it
|
||||||
platform_config: Vec<Box<dyn Any>>,
|
unsafe {
|
||||||
) -> ! {
|
let mut main_fn_ptr = libc::dlsym(libc::RTLD_DEFAULT, b"main\0".as_ptr() as _);
|
||||||
let mut virtual_dom = VirtualDom::new(root);
|
|
||||||
|
|
||||||
for context in contexts {
|
if main_fn_ptr.is_null() {
|
||||||
virtual_dom.insert_any_root_context(context());
|
main_fn_ptr = libc::dlsym(libc::RTLD_DEFAULT, b"_main\0".as_ptr() as _);
|
||||||
}
|
}
|
||||||
|
|
||||||
let platform_config = *platform_config
|
if main_fn_ptr.is_null() {
|
||||||
.into_iter()
|
panic!("Failed to find main symbol");
|
||||||
.find_map(|cfg| cfg.downcast::<Config>().ok())
|
}
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -19,7 +19,11 @@ const EVENTS_PATH: &str = "http://dioxus.index.html/__events";
|
|||||||
#[cfg(not(any(target_os = "android", target_os = "windows")))]
|
#[cfg(not(any(target_os = "android", target_os = "windows")))]
|
||||||
const EVENTS_PATH: &str = "dioxus://index.html/__events";
|
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
|
#[allow(clippy::too_many_arguments)] // just for now, should fix this eventually
|
||||||
/// Handle a request from the webview
|
/// Handle a request from the webview
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ use dioxus_history::{History, MemoryHistory};
|
|||||||
use dioxus_hooks::to_owned;
|
use dioxus_hooks::to_owned;
|
||||||
use dioxus_html::{HasFileData, HtmlEvent, PlatformEventData};
|
use dioxus_html::{HasFileData, HtmlEvent, PlatformEventData};
|
||||||
use futures_util::{pin_mut, FutureExt};
|
use futures_util::{pin_mut, FutureExt};
|
||||||
use std::cell::OnceCell;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::{cell::OnceCell, time::Duration};
|
||||||
use std::{rc::Rc, task::Waker};
|
use std::{rc::Rc, task::Waker};
|
||||||
use wry::{DragDropEvent, RequestAsyncResponder, WebContext, WebViewBuilder};
|
use wry::{DragDropEvent, RequestAsyncResponder, WebContext, WebViewBuilder};
|
||||||
|
|
||||||
@@ -480,6 +480,31 @@ impl WebviewInstance {
|
|||||||
.webview
|
.webview
|
||||||
.evaluate_script("window.interpreter.kickAllStylesheetsOnPage()");
|
.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
|
/// A synchronous response to a browser event which may prevent the default browser's action
|
||||||
|
|||||||
@@ -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.
|
/// 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"))]
|
#[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 || {
|
std::thread::spawn(move || {
|
||||||
let uri = format!(
|
let uri = format!(
|
||||||
"{endpoint}?aslr_reference={}&build_id={}",
|
"{endpoint}?aslr_reference={}&build_id={}",
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ router = ["dep:dioxus-router"]
|
|||||||
# Platforms
|
# Platforms
|
||||||
fullstack = ["dep:dioxus-fullstack", "dioxus-config-macro/fullstack", "dep:serde"]
|
fullstack = ["dep:dioxus-fullstack", "dioxus-config-macro/fullstack", "dep:serde"]
|
||||||
desktop = ["dep:dioxus-desktop", "dioxus-fullstack?/desktop", "dioxus-config-macro/desktop"]
|
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 = [
|
web = [
|
||||||
"dep:dioxus-web",
|
"dep:dioxus-web",
|
||||||
"dioxus-fullstack?/web",
|
"dioxus-fullstack?/web",
|
||||||
|
|||||||
@@ -332,12 +332,12 @@ impl LaunchBuilder {
|
|||||||
|
|
||||||
#[cfg(feature = "mobile")]
|
#[cfg(feature = "mobile")]
|
||||||
if matches!(platform, KnownPlatform::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")]
|
#[cfg(feature = "desktop")]
|
||||||
if matches!(platform, KnownPlatform::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")]
|
#[cfg(feature = "server")]
|
||||||
|
|||||||
@@ -119,9 +119,7 @@ pub async fn run(mut vdom: VirtualDom, ws: impl LiveViewSocket) -> Result<(), Li
|
|||||||
#[cfg(all(feature = "devtools", debug_assertions))]
|
#[cfg(all(feature = "devtools", debug_assertions))]
|
||||||
let mut hot_reload_rx = {
|
let mut hot_reload_rx = {
|
||||||
let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
|
let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
|
||||||
if let Some(endpoint) = dioxus_cli_config::devserver_ws_endpoint() {
|
dioxus_devtools::connect(move |template| _ = tx.send(template));
|
||||||
dioxus_devtools::connect(endpoint, move |template| _ = tx.send(template));
|
|
||||||
}
|
|
||||||
rx
|
rx
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+1
-139
@@ -5,23 +5,6 @@
|
|||||||
pub use dioxus_desktop::*;
|
pub use dioxus_desktop::*;
|
||||||
use dioxus_lib::prelude::*;
|
use dioxus_lib::prelude::*;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::sync::Mutex;
|
|
||||||
|
|
||||||
pub mod launch_bindings {
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
pub fn launch(
|
|
||||||
root: fn() -> Element,
|
|
||||||
contexts: Vec<Box<dyn Fn() -> Box<dyn Any> + Send + Sync>>,
|
|
||||||
platform_config: Vec<Box<dyn Any>>,
|
|
||||||
) {
|
|
||||||
super::launch_cfg(root, contexts, platform_config);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn launch_virtual_dom(_virtual_dom: VirtualDom, _desktop_config: Config) -> ! {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Launch via the binding API
|
/// Launch via the binding API
|
||||||
pub fn launch(root: fn() -> Element) {
|
pub fn launch(root: fn() -> Element) {
|
||||||
@@ -33,126 +16,5 @@ pub fn launch_cfg(
|
|||||||
contexts: Vec<Box<dyn Fn() -> Box<dyn Any> + Send + Sync>>,
|
contexts: Vec<Box<dyn Fn() -> Box<dyn Any> + Send + Sync>>,
|
||||||
platform_config: Vec<Box<dyn Any>>,
|
platform_config: Vec<Box<dyn Any>>,
|
||||||
) {
|
) {
|
||||||
#[cfg(target_os = "android")]
|
dioxus_desktop::launch::launch_cfg(root, contexts, platform_config);
|
||||||
{
|
|
||||||
*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<T> is technically safe
|
|
||||||
/// to move between threads if you can prove that no other thread is using the Rc<T> 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<dyn Fn() -> Box<dyn Any> + Send + Sync>>,
|
|
||||||
platform_config: Vec<Box<dyn Any>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Send for BoundLaunchObjects {}
|
|
||||||
unsafe impl Sync for BoundLaunchObjects {}
|
|
||||||
|
|
||||||
static APP_OBJECTS: Mutex<Option<BoundLaunchObjects>> = 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -69,13 +69,11 @@ pub fn launch_cfg_with_props<P: Clone + 'static, M: 'static>(
|
|||||||
))]
|
))]
|
||||||
{
|
{
|
||||||
use crate::event::DioxusNativeEvent;
|
use crate::event::DioxusNativeEvent;
|
||||||
if let Some(endpoint) = dioxus_cli_config::devserver_ws_endpoint() {
|
let proxy = event_loop.create_proxy();
|
||||||
let proxy = event_loop.create_proxy();
|
dioxus_devtools::connect(move |event| {
|
||||||
dioxus_devtools::connect(endpoint, move |event| {
|
let dxn_event = DioxusNativeEvent::DevserverEvent(event);
|
||||||
let dxn_event = DioxusNativeEvent::DevserverEvent(event);
|
let _ = proxy.send_event(BlitzShellEvent::embedder_event(dxn_event));
|
||||||
let _ = proxy.send_event(BlitzShellEvent::embedder_event(dxn_event));
|
})
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spin up the virtualdom
|
// Spin up the virtualdom
|
||||||
|
|||||||
@@ -51,11 +51,7 @@ async fn serve_server(
|
|||||||
) {
|
) {
|
||||||
let (devtools_tx, mut devtools_rx) = futures_channel::mpsc::unbounded();
|
let (devtools_tx, mut devtools_rx) = futures_channel::mpsc::unbounded();
|
||||||
|
|
||||||
if let Some(endpoint) = dioxus_cli_config::devserver_ws_endpoint() {
|
dioxus_devtools::connect(move |msg| _ = devtools_tx.unbounded_send(msg));
|
||||||
dioxus_devtools::connect(endpoint, move |msg| {
|
|
||||||
_ = devtools_tx.unbounded_send(msg);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
let platform_config = platform_config
|
let platform_config = platform_config
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|||||||
@@ -756,8 +756,6 @@ macro_rules! impl_hot_function {
|
|||||||
unsafe fn call_as_ptr(&mut self, args: ($($arg,)*)) -> Self::Return {
|
unsafe fn call_as_ptr(&mut self, args: ($($arg,)*)) -> Self::Return {
|
||||||
unsafe {
|
unsafe {
|
||||||
if let Some(jump_table) = get_jump_table() {
|
if let Some(jump_table) = get_jump_table() {
|
||||||
|
|
||||||
|
|
||||||
let real = std::mem::transmute_copy::<Self, Self::Real>(&self) as *const ();
|
let real = std::mem::transmute_copy::<Self, Self::Real>(&self) as *const ();
|
||||||
|
|
||||||
// Android implements MTE / pointer tagging and we need to preserve the tag.
|
// 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
|
// 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.
|
// 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(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;
|
#[cfg(target_pointer_width = "64")] let real = real as u64;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasm-split-cli"
|
name = "wasm-split-cli"
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
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]
|
[dependencies]
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasm-split-macro"
|
name = "wasm-split-macro"
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
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]
|
[dependencies]
|
||||||
syn = { workspace = true, features = ["full"] }
|
syn = { workspace = true, features = ["full"] }
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasm-split"
|
name = "wasm-split"
|
||||||
version = "0.1.0"
|
version = { workspace = true }
|
||||||
edition = "2021"
|
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]
|
[dependencies]
|
||||||
async-once-cell = { workspace = true, features = ["std"] }
|
async-once-cell = { workspace = true, features = ["std"] }
|
||||||
|
|||||||
Reference in new issue
Block a user