7.6 KiB
Dioxus CLI Architecture
The dx CLI is a comprehensive build tool for Dioxus applications, supporting development, building, bundling, and cross-platform deployment.
Command Structure
Entry point: main.rs with async tokio runtime and TraceController for error handling.
Commands Enum
Serve- Watch and serve with hot-reloadingBuild- Full production buildBundle- Package for distributionRun- Run without hot-reloadCreate/Init- Project scaffoldingCheck- Lint/validate RSXTranslate- Convert HTML/JSX to RSXAutoformat- Format RSX codeConfig- Manage Dioxus.tomlDoctor- Diagnose environmentComponents- Component registrySelfUpdate- Update CLITools- Internal tools (build-assets, hotpatch)
Platform Support
Platform Enum
Web- wasm32-unknown-unknownMacOS/Windows/Linux- Desktop webviewIos/Android- Mobile webviewServer- SSR/fullstack serverLiveview- WebSocket streamingUnknown- Auto-select
CommandWithPlatformOverrides
Allows separate client/server args for fullstack:
dx serve @client --features web @server --features server
Decomposes into client BuildArgs, server BuildArgs, and shared args.
Build System
BuildRequest
The "plan" for a single build:
BuildRequest
├── workspace: Workspace metadata
├── config: DioxusConfig
├── package: Package details
├── features: Vec<String>
├── target: Triple
├── bundle: BundleFormat
├── profile: Profile
├── rustflags: Vec<String>
└── custom_linker: Option<PathBuf>
Responsible for:
- Writing build artifacts
- Processing assets
- Writing platform-specific metadata (Info.plist, AndroidManifest.xml)
- Platform-specific linking (Android uses dx as opaque linker, hotpatching uses custom linker)
BuildMode Enum
Base { run: bool }- Normal cargo rustc buildFat- Full build with all symbols for hot-patchingThin { rustc_args, changed_files, aslr_reference, cache }- Fast rebuild
BuildContext
Runtime configuration with progress channel:
ProgressTxfor status updatesBuildIdenum: PRIMARY (client), SECONDARY (server)- Helper methods:
compiling(),linking(),bindgen(), etc.
AppBuilder
State machine managing ongoing builds:
- Build task handle and artifacts
- App child process (stdout/stderr)
- Hot-patching state (patches, module cache, ASLR offset)
- Build metadata: stage, compiled crates, timing
Dev Server (Serve)
AppServer (runner.rs)
Primary orchestration:
AppServer
├── workspace: Workspace metadata
├── client / server: AppBuilder instances
├── watcher: File system watcher
├── file_map: Cached RSX files for hot-reload diffing
├── devserver: WebServer
└── flags: use_hotpatch_engine, automatic_rebuilds, hot_reload, etc.
WebServer (server.rs)
HTTP + WebSocket server providing:
- Hot-reload socket - RSX and asset updates
- Build-status socket - Compilation progress
- HTTP server - Static assets (public folder, WASM)
- Proxy support - Fullstack backend
- DevTools - Connected clients with build_id, ASLR reference, PID
Output (output.rs)
Terminal UI with ratatui:
- Build progress with crate-by-crate counts
- Asset copying progress
- Colored output, throbber animations
- Keyboard input (r=rebuild, p=pause, v=verbose)
- 100ms tick-based rendering
File Change Handling
File modified → detect type
├── Rust file → diff RSX using dioxus_rsx_hotreload::diff_rsx()
│ ├── Extract changed templates
│ ├── Build HotReloadMsg
│ └── Send via WebSocket
├── Asset file → copy to bundle, signal reload
└── If can't hot-reload → queue full rebuild
serve_all() Main Loop
Uses tokio::select! to multiplex:
- Builder updates (compilation, process output)
- WebServer events (connections, messages)
- Output (TUI updates, input)
- TraceController (panic handling)
- File watcher (filesystem changes)
Asset Processing
Pipeline (build/assets.rs)
- Manganis Integration - Extract
__ASSETS__symbols from binary - Asset Hashing - Compute hashes for cache-busting
- Two Format Support - Legacy (0.7.0-0.7.1) and New (0.7.2+) serialization
- Platform Paths - Assets relative to executable; Android uses "asset root"
Processing by Type
- Images: Resize, convert format (Avif, WebP), optimize
- CSS/JS: Minify, hash-suffix naming
- Folders: Recursive copy
- Unknown: Direct copy with optional hash
Bundling
Bundle System
Platform-specific packaging:
- Web/Server: No special bundling, outputs to web/ directory
- Desktop: Uses tauri-bundler (dmg, msi, appimage)
- iOS: App bundle format with codesigning warnings
- Android: Runs
gradle bundleReleasefor AAB
BundleConfig
BundleConfig
├── identifier: String
├── publisher: String
├── icon: Vec<PathBuf>
├── resources: Vec<PathBuf>
├── deb / macos / windows / android: Platform-specific
Hot-Patching
HotpatchModuleCache
Caches compiled dependency symbols:
- Symbol table with function/data info
- Pre-computed for Fat builds
- Reused in Thin builds for fast linking
Patch Creation Flow
- Compile app with Fat mode (all symbols)
- On change: compile Thin (small, fast)
- Analyze binary diff → create JumpTable
- Apply patches to running executable
- If patch fails → fall back to full rebuild
Platform Implementations
create_windows_jump_table()- x86/x64 jump stubscreate_native_jump_table()- macOS/Linux function overridescreate_wasm_jump_table()- WASM indirect call table updates
Configuration
DioxusConfig (Dioxus.toml)
[application]
asset_dir = "assets"
out_dir = "dist"
tailwind_input/output = "..."
ios_info_plist = "Info.plist"
android_manifest = "AndroidManifest.xml"
[web]
app.title = "My App"
https.enabled = true
pre_compress = false
[bundle]
identifier = "com.example.app"
publisher = "Company"
Resolution Order
- Default values
- Dioxus.toml in project root
- CLI argument overrides
- Environment variables
Workspace
Workspace Struct (Singleton)
Workspace
├── krates: Krates (cargo metadata, dependency graph)
├── settings: CliSettings (user settings ~/.config/dioxus/)
├── sysroot: Rust target sysroot
├── rustc_version: Version
├── wasm_opt: Optional path
├── cargo_toml: Parsed Cargo.toml
└── android_tools: Optional NDK/SDK
Lazy-loaded via Workspace::current() with tokio Mutex.
Extension Points
Adding New Bundlers
- New variant in
BundleFormatenum - New variant in
Rendererenum - New config struct (e.g.,
MyPlatformSettings) - Implementation in
Bundle::bundle() - Asset directory structure definition
- Linking strategy if needed
Adding New Commands
- New variant in
Commandsenum - New command module in
cli/ - Register in
TraceController::main()match - Optional
StructuredOutputvariant for results
Customizing Build Hooks
- Pre/post-build scripts in Dioxus.toml
- Custom linker integration
- Asset transformation pipeline
Key Patterns
Channel-Based Progress
Build Task → BuilderUpdate Channel → AppBuilder → ServeUpdate → Output TUI
Decouples build process from UI for real-time updates.
Lazy Workspace Loading
Single workspace load with tokio Mutex, shows spinner if cargo-metadata takes >1 second.
Renderer/Bundle Inference
- Explicit flags:
--web,--webview,--native - Platform aliases:
--ios,--android,--desktop - Feature detection from Cargo.toml
- Default: Infer from target triple