Bläddra i källkod

feat: integrate dioxus-logger inline (#3302)

* feat: integrate dioxus-logger inline

* remove log/simple logger references

* fix: add dioxus-data-id-0 to root elements to not emit errors internally

* drop config.toml and use cargo.toml profiles instead

* make clippy happy with the unit value lint

* feat: better presentation for logging
Jonathan Kelley 6 månader sedan
förälder
incheckning
7d490dc3bd

+ 0 - 14
.cargo/config.toml

@@ -1,14 +0,0 @@
-[profile]
-
-[profile.dioxus-wasm]
-inherits = "dev"
-opt-level = 2
-
-[profile.dioxus-server]
-inherits = "dev"
-opt-level = 2
-
-[profile.dioxus-android]
-inherits = "dev"
-opt-level = 1
-debug = 0

+ 7 - 57
Cargo.lock

@@ -2413,16 +2413,6 @@ version = "1.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
 
-[[package]]
-name = "colored"
-version = "2.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8"
-dependencies = [
- "lazy_static",
- "windows-sys 0.48.0",
-]
-
 [[package]]
 name = "com"
 version = "0.6.0"
@@ -3400,6 +3390,7 @@ dependencies = [
  "dioxus-hooks",
  "dioxus-html",
  "dioxus-liveview",
+ "dioxus-logger",
  "dioxus-mobile",
  "dioxus-router",
  "dioxus-signals",
@@ -4005,12 +3996,13 @@ dependencies = [
 
 [[package]]
 name = "dioxus-logger"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d7cbab0b5519060fe9e14b3c21e3f2329b8386cd905618f78c7b929cd00cf54"
+version = "0.6.0-rc.0"
 dependencies = [
- "log",
- "web-sys",
+ "console_error_panic_hook",
+ "dioxus-cli-config",
+ "tracing",
+ "tracing-subscriber",
+ "tracing-wasm",
 ]
 
 [[package]]
@@ -4057,10 +4049,7 @@ dependencies = [
 name = "dioxus-pwa-example"
 version = "0.1.0"
 dependencies = [
- "console_error_panic_hook",
  "dioxus",
- "log",
- "wasm-logger",
 ]
 
 [[package]]
@@ -4154,7 +4143,6 @@ dependencies = [
  "reqwest 0.12.9",
  "rustc-hash 1.1.0",
  "serde",
- "simple_logger",
  "tokio",
  "tracing",
  "tracing-subscriber",
@@ -4186,7 +4174,6 @@ version = "0.6.0-rc.0"
 dependencies = [
  "async-trait",
  "ciborium",
- "console_error_panic_hook",
  "dioxus",
  "dioxus-cli-config",
  "dioxus-core",
@@ -4845,8 +4832,6 @@ name = "file-explorer"
 version = "0.1.0"
 dependencies = [
  "dioxus",
- "dioxus-logger",
- "log",
  "open",
 ]
 
@@ -5035,7 +5020,6 @@ dependencies = [
  "execute",
  "http 1.1.0",
  "serde",
- "simple_logger",
  "sqlx",
  "tokio",
  "tower 0.4.13",
@@ -5058,9 +5042,6 @@ dependencies = [
  "dioxus",
  "reqwest 0.12.9",
  "serde",
- "tracing",
- "tracing-subscriber",
- "tracing-wasm",
 ]
 
 [[package]]
@@ -5070,10 +5051,6 @@ dependencies = [
  "dioxus",
  "reqwest 0.12.9",
  "serde",
- "simple_logger",
- "tracing",
- "tracing-subscriber",
- "tracing-wasm",
 ]
 
 [[package]]
@@ -5095,11 +5072,7 @@ dependencies = [
  "futures-util",
  "once_cell",
  "serde",
- "simple_logger",
  "tokio",
- "tracing",
- "tracing-subscriber",
- "tracing-wasm",
 ]
 
 [[package]]
@@ -11346,18 +11319,6 @@ dependencies = [
  "time",
 ]
 
-[[package]]
-name = "simple_logger"
-version = "4.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e7e46c8c90251d47d08b28b8a419ffb4aede0f87c2eea95e17d1d5bacbf3ef1"
-dependencies = [
- "colored",
- "log",
- "time",
- "windows-sys 0.48.0",
-]
-
 [[package]]
 name = "siphasher"
 version = "0.3.11"
@@ -15106,17 +15067,6 @@ dependencies = [
  "leb128",
 ]
 
-[[package]]
-name = "wasm-logger"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "074649a66bb306c8f2068c9016395fa65d8e08d2affcbf95acf3c24c3ab19718"
-dependencies = [
- "log",
- "wasm-bindgen",
- "web-sys",
-]
-
 [[package]]
 name = "wasm-opt"
 version = "0.116.1"

+ 20 - 2
Cargo.toml

@@ -64,6 +64,7 @@ members = [
     "packages/const-serialize",
     "packages/const-serialize-macro",
     "packages/dx-wire-format",
+    "packages/logger",
 
     # Playwright tests
     "packages/playwright-tests/liveview",
@@ -138,7 +139,7 @@ dioxus-devtools-types = { path = "packages/devtools-types", version = "0.6.0-rc.
 dioxus-fullstack = { path = "packages/fullstack", version = "0.6.0-rc.0" }
 dioxus_server_macro = { path = "packages/server-macro", version = "0.6.0-rc.0", default-features = false }
 dioxus-dx-wire-format = { path = "packages/dx-wire-format", version = "0.6.0-rc.0" }
-
+dioxus-logger = { path = "packages/logger", version = "0.6.0-rc.0" }
 const-serialize = { path = "packages/const-serialize", version = "0.6.0-rc.0" }
 const-serialize-macro = { path = "packages/const-serialize-macro", version = "0.6.0-rc.0" }
 generational-box = { path = "packages/generational-box", version = "0.6.0-rc.0" }
@@ -157,10 +158,12 @@ clap = { version = "4.5.7" }
 askama_escape = "0.10.3"
 tracing = "0.1.37"
 tracing-futures = "0.2.5"
+tracing-subscriber = { version = "0.3.18", default-features = false }
 toml = "0.8"
 tokio = "1.40"
 slab = "0.4.2"
 slotmap = { version = "1.0.7", features = ["serde"] }
+futures = "0.3.30"
 futures-channel = "0.3.21"
 futures-util = { version = "0.3", default-features = false }
 rustc-hash = "1.1.0"
@@ -207,7 +210,6 @@ fluent-uri = { version = "0.2.0", features = ["serde"] }
 internment = { version = "0.7.0" }
 proc-macro2-diagnostics = { version = "0.10", default-features = false }
 env_logger = "0.11.0"
-tracing-subscriber = "0.3.17"
 chrono = { version = "0.4.34" }
 gloo = { version = "0.8.0" }
 gloo-utils = { version = "0.1.6" }
@@ -222,6 +224,8 @@ cargo-config2 = "0.1.26"
 criterion = { version = "0.5" }
 walrus = "0.23.2"
 cargo_metadata = "0.18.1"
+tracing-wasm = "0.2.1"
+console_error_panic_hook = "0.1.7"
 
 # desktop
 wry = { version = "0.45.0", default-features = false }
@@ -260,6 +264,16 @@ inherits = "dev"
 debug-assertions = false
 incremental = true
 
+[profile.wasm-dev]
+inherits = "dev"
+opt-level = 1
+
+[profile.server-dev]
+inherits = "dev"
+
+[profile.android-dev]
+inherits = "dev"
+
 # This is a "virtual package"
 # It is not meant to be published, but is used so "cargo run --example XYZ" works properly
 [package]
@@ -473,3 +487,7 @@ doc-scrape-examples = true
 [[example]]
 name = "eval"
 doc-scrape-examples = true
+
+[[example]]
+name = "logging"
+doc-scrape-examples = true

+ 0 - 4
example-projects/file-explorer/Cargo.toml

@@ -8,8 +8,4 @@ publish = false
 
 [dependencies]
 dioxus = { workspace = true, features = ["desktop"] }
-
-# Debug
-log = "0.4.19"
-dioxus-logger = "0.4.1"
 open = "5.1.2"

+ 0 - 3
example-projects/fullstack-hackernews/Cargo.toml

@@ -12,9 +12,6 @@ dioxus = { workspace = true, features = ["fullstack", "router"] }
 chrono = { version = "0.4.38", features = ["serde"] }
 reqwest = { workspace= true, features = ["json"] }
 serde = { workspace = true, features = ["derive"] }
-tracing-wasm = "0.2.1"
-tracing = { workspace = true }
-tracing-subscriber = "0.3.17"
 
 [features]
 default = []

+ 0 - 6
example-projects/fullstack-hackernews/src/main.rs

@@ -11,12 +11,6 @@ use std::{
 use svg_attributes::to;
 
 fn main() {
-    #[cfg(feature = "web")]
-    tracing_wasm::set_as_global_default();
-
-    #[cfg(feature = "server")]
-    tracing_subscriber::fmt::init();
-
     LaunchBuilder::new()
         .with_cfg(server_only! {
             dioxus::fullstack::ServeConfig::builder().enable_out_of_order_streaming()

+ 1 - 2
examples/fullstack-auth/Cargo.toml

@@ -14,7 +14,6 @@ dioxus-fullstack = { workspace = true }
 axum = { workspace = true, optional = true }
 tokio = { workspace = true, features = ["full"], optional = true }
 tower-http = { workspace = true, features = ["auth"], optional = true }
-simple_logger = { version = "4.2.0", optional = true }
 async-trait = { version = "0.1.71", optional = true }
 sqlx = { version = "0.7.0", features = [
     "macros",
@@ -44,5 +43,5 @@ optional = true
 
 [features]
 default = []
-server = ["axum", "tokio", "dioxus-fullstack/axum", "tower-http", "simple_logger", "async-trait", "sqlx", "axum_session", "axum_session_auth", "http", "tower"]
+server = ["axum", "tokio", "dioxus-fullstack/axum", "tower-http", "async-trait", "sqlx", "axum_session", "axum_session_auth", "http", "tower"]
 web = ["dioxus-web"]

+ 3 - 1
examples/fullstack-auth/src/main.rs

@@ -15,6 +15,9 @@ use dioxus_fullstack::prelude::*;
 use serde::{Deserialize, Serialize};
 
 fn main() {
+    // Set the logger ahead of time since we don't use `dioxus::launch` on the server
+    dioxus::logger::initialize_default();
+
     #[cfg(feature = "web")]
     // Hydrate the application on the client
     dioxus_web::launch::launch_cfg(app, dioxus_web::Config::new().hydrate(true));
@@ -27,7 +30,6 @@ fn main() {
         use axum_session::SessionStore;
         use axum_session_auth::AuthConfig;
         use axum_session_auth::SessionSqlitePool;
-        simple_logger::SimpleLogger::new().init().unwrap();
         tokio::runtime::Runtime::new()
             .unwrap()
             .block_on(async move {

+ 0 - 4
examples/fullstack-hello-world/Cargo.toml

@@ -9,10 +9,6 @@ publish = false
 [dependencies]
 dioxus = { workspace = true, features = ["fullstack"]}
 serde = "1.0.159"
-simple_logger = "4.2.0"
-tracing-wasm = "0.2.1"
-tracing = { workspace = true }
-tracing-subscriber = "0.3.17"
 reqwest = { workspace = true }
 
 [features]

+ 0 - 6
examples/fullstack-hello-world/src/main.rs

@@ -45,11 +45,5 @@ async fn get_server_data() -> Result<String, ServerFnError> {
 }
 
 fn main() {
-    #[cfg(feature = "web")]
-    tracing_wasm::set_as_global_default();
-
-    #[cfg(feature = "server")]
-    tracing_subscriber::fmt::init();
-
     dioxus::launch(app);
 }

+ 3 - 7
examples/fullstack-streaming/Cargo.toml

@@ -8,15 +8,11 @@ publish = false
 
 [dependencies]
 dioxus = { workspace = true, features = ["fullstack"] }
-serde = "1.0.159"
-simple_logger = "4.2.0"
-tracing-wasm = "0.2.1"
-tracing.workspace = true
-tracing-subscriber = "0.3.17"
-futures = "0.3.30"
+serde = { workspace = true }
+futures = { workspace = true }
 tokio = { workspace = true, optional = true }
 futures-util.workspace = true
-once_cell = "1.19.0"
+once_cell = { workspace = true }
 
 [features]
 default = []

+ 1 - 0
examples/fullstack-streaming/src/main.rs

@@ -29,6 +29,7 @@ pub async fn test_stream() -> Result<TextStream, ServerFnError> {
     tokio::spawn(async move {
         loop {
             tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
+            dioxus::logger::tracing::info!("Sending new chunk!");
             let _ = tx.unbounded_send(Ok("Hello, world!".to_string()));
         }
     });

+ 43 - 0
examples/logging.rs

@@ -0,0 +1,43 @@
+//! Dioxus ships out-of-the-box with tracing hooks that integrate with the Dioxus-CLI.
+//!
+//! The built-in tracing-subscriber automatically sets up a wasm panic hook and wires up output
+//! to be consumed in a machine-readable format when running under `dx`.
+//!
+//! You can disable the built-in tracing-subscriber or customize the log level yourself.
+//!
+//! By default:
+//! - in `dev` mode, the default log output is `debug`
+//! - in `release` mode, the default log output is `info`
+//!
+//! To use the dioxus logger in your app, simply call any of the tracing functions (info!(), warn!(), error!())
+
+use dioxus::logger::tracing::{debug, error, info, warn};
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::launch(app);
+}
+
+fn app() -> Element {
+    rsx! {
+        div {
+            h1 { "Logger demo" }
+            button {
+                onclick: move |_| warn!("Here's a warning!"),
+                "Warn!"
+            }
+            button {
+                onclick: move |_| error!("Here's an error!"),
+                "Error!"
+            }
+            button {
+                onclick: move |_| debug!("Here's a debug"),
+                "Debug!"
+            }
+            button {
+                onclick: move |_| info!("Here's an info!"),
+                "Info!"
+            }
+        }
+    }
+}

+ 0 - 6
examples/pwa/Cargo.toml

@@ -9,9 +9,3 @@ publish = false
 
 [dependencies]
 dioxus = { workspace = true, features = ["web"] }
-
-log = "0.4.6"
-
-# WebAssembly Debug
-wasm-logger = "0.2.0"
-console_error_panic_hook = "0.1.7"

+ 1 - 7
examples/pwa/src/main.rs

@@ -1,10 +1,6 @@
 use dioxus::prelude::*;
 
 fn main() {
-    // init debug tool for WebAssembly
-    wasm_logger::init(wasm_logger::Config::default());
-    console_error_panic_hook::set_once();
-
     dioxus::launch(app);
 }
 
@@ -13,9 +9,7 @@ fn app() -> Element {
         div { style: "text-align: center;",
             h1 { "🌗 Dioxus 🚀" }
             h3 { "Frontend that scales." }
-            p {
-                "Dioxus is a portable, performant, and ergonomic framework for building cross-platform user interfaces in Rust."
-            }
+            p { "Build web, desktop, and mobile apps with Dioxus" }
         }
     )
 }

+ 5 - 5
examples/tailwind/Cargo.toml

@@ -12,9 +12,9 @@ publish = false
 
 [dependencies]
 manganis = { workspace = true }
+dioxus = { workspace = true }
 
-[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
-dioxus = { path = "../../packages/dioxus", features = ["desktop"] }
-
-[target.'cfg(target_arch = "wasm32")'.dependencies]
-dioxus = { path = "../../packages/dioxus", features = ["web"] }
+[features]
+default = ["desktop"]
+web = ["dioxus/web"]
+desktop = ["dioxus/desktop"]

+ 10 - 9
examples/tailwind/src/main.rs

@@ -1,14 +1,13 @@
-#![allow(non_snake_case)]
-
 use dioxus::prelude::*;
 
 fn main() {
     dioxus::launch(app);
 }
 
-pub fn app() -> Element {
+fn app() -> Element {
     let grey_background = true;
-    rsx! (
+
+    rsx! {
         document::Link { rel: "stylesheet", href: asset!("/public/tailwind.css") }
         div {
             header {
@@ -66,11 +65,12 @@ pub fn app() -> Element {
                 }
             }
         }
-    )
+    }
 }
 
+#[component]
 pub fn StacksIcon() -> Element {
-    rsx!(
+    rsx! {
         svg {
             fill: "none",
             stroke: "currentColor",
@@ -81,11 +81,12 @@ pub fn StacksIcon() -> Element {
             view_box: "0 0 24 24",
             path { d: "M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5" }
         }
-    )
+    }
 }
 
+#[component]
 pub fn RightArrowIcon() -> Element {
-    rsx!(
+    rsx! {
         svg {
             fill: "none",
             stroke: "currentColor",
@@ -96,5 +97,5 @@ pub fn RightArrowIcon() -> Element {
             view_box: "0 0 24 24",
             path { d: "M5 12h14M12 5l7 7-7 7" }
         }
-    )
+    }
 }

+ 1 - 1
packages/cli/Cargo.toml

@@ -91,7 +91,7 @@ ignore = "0.4.22"
 env_logger = { workspace = true }
 const-serialize = { workspace = true, features = ["serde"] }
 
-tracing-subscriber = { version = "0.3.18", features = ["std", "env-filter", "json"] }
+tracing-subscriber = { version = "0.3.18", features = ["std", "env-filter", "json", "registry", "fmt"] }
 console-subscriber = { version = "0.3.0", optional = true }
 tracing = { workspace = true }
 wasm-opt = { version = "0.116.1", optional = true }

+ 1 - 1
packages/config-macro/src/lib.rs

@@ -19,7 +19,7 @@ macro_rules! define_config_macro {
                 }
             } else {
                 quote! {
-                    {}
+                    ()
                 }
             }
             .into()

+ 1 - 1
packages/core/Cargo.toml

@@ -31,7 +31,7 @@ dioxus-html = { workspace = true, features = ["serialize"] }
 tokio = { workspace = true, features = ["full"] }
 rand = { workspace = true }
 reqwest = { workspace = true }
-tracing-subscriber = { workspace = true }
+tracing-subscriber = { workspace = true, default-features = true }
 tracing-fluent-assertions = "0.3.0"
 pretty_assertions = "1.3.0"
 

+ 0 - 1
packages/desktop/src/webview.rs

@@ -69,7 +69,6 @@ impl WebviewEdits {
                 self.handle_html_event(event)
             }
             Err(err) => {
-                tracing::error!("cannot decippher format of user event");
                 tracing::error!(
                     "Error parsing user_event: {:?}.Contents: {:?}, raw: {:#?}",
                     err,

+ 3 - 1
packages/dioxus/Cargo.toml

@@ -27,6 +27,7 @@ dioxus-fullstack = { workspace = true, default-features = true, optional = true
 dioxus-liveview = { workspace = true, optional = true }
 dioxus-ssr = { workspace = true, optional = true }
 manganis = { workspace = true, features = ["dioxus"], optional = true }
+dioxus-logger = { workspace = true, optional = true }
 
 serde = { version = "1.0.136", optional = true }
 dioxus-cli-config = { workspace = true, optional = true }
@@ -35,7 +36,7 @@ dioxus-cli-config = { workspace = true, optional = true }
 dioxus-devtools = { workspace = true, optional = true }
 
 [features]
-default = ["macro", "html", "devtools", "signals", "hooks", "launch", "mounted", "file_engine", "document", "asset"]
+default = ["macro", "html", "signals", "hooks", "launch",  "mounted", "file_engine", "document", "asset", "devtools", "logger"]
 minimal = ["macro", "html", "signals", "hooks", "launch"]
 signals = ["dep:dioxus-signals"]
 macro = ["dep:dioxus-core-macro"]
@@ -46,6 +47,7 @@ mounted = ["dioxus-web?/mounted", "dioxus-html?/mounted"]
 file_engine = ["dioxus-web?/file_engine"]
 asset = ["dep:manganis"]
 document = ["dioxus-web?/document", "dep:dioxus-document", "dep:dioxus-history"]
+logger = ["dep:dioxus-logger"]
 
 launch = ["dep:dioxus-config-macro"]
 router = ["dep:dioxus-router"]

+ 3 - 0
packages/dioxus/src/launch.rs

@@ -155,6 +155,9 @@ impl LaunchBuilder {
     }
 
     fn launch_inner(self, app: fn() -> Element) {
+        #[cfg(feature = "logger")]
+        dioxus_logger::initialize_default();
+
         #[cfg(all(feature = "fullstack", any(feature = "desktop", feature = "mobile")))]
         {
             use dioxus_fullstack::prelude::server_fn::client::{get_server_url, set_server_url};

+ 4 - 0
packages/dioxus/src/lib.rs

@@ -65,6 +65,10 @@ pub use dioxus_html as html;
 #[cfg_attr(docsrs, doc(cfg(feature = "macro")))]
 pub use dioxus_core_macro as core_macro;
 
+#[cfg(feature = "logger")]
+#[cfg_attr(docsrs, doc(cfg(feature = "logger")))]
+pub use dioxus_logger as logger;
+
 pub mod prelude {
     #[cfg(feature = "document")]
     #[cfg_attr(docsrs, doc(cfg(feature = "document")))]

+ 1 - 2
packages/fullstack/Cargo.toml

@@ -77,8 +77,7 @@ tokio = { workspace = true, features = ["rt", "sync", "rt-multi-thread"], option
 dioxus = { workspace = true, features = ["fullstack"] }
 
 [features]
-default = ["devtools", "panic_hook", "document", "file_engine", "mounted"]
-panic_hook = ["dioxus-web?/panic_hook"]
+default = ["devtools", "document", "file_engine", "mounted"]
 devtools = ["dioxus-web?/devtools", "dep:dioxus-devtools"]
 mounted = ["dioxus-web?/mounted"]
 file_engine = ["dioxus-web?/file_engine"]

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

@@ -1 +1 @@
-function setAttributeInner(node,field,value,ns){if(ns==="style"){node.style.setProperty(field,value);return}if(ns){node.setAttributeNS(ns,field,value);return}switch(field){case"value":if(node.value!==value)node.value=value;break;case"initial_value":node.defaultValue=value;break;case"checked":node.checked=truthy(value);break;case"initial_checked":node.defaultChecked=truthy(value);break;case"selected":node.selected=truthy(value);break;case"initial_selected":node.defaultSelected=truthy(value);break;case"dangerous_inner_html":node.innerHTML=value;break;default:if(!truthy(value)&&isBoolAttr(field))node.removeAttribute(field);else node.setAttribute(field,value)}}var truthy=function(val){return val==="true"||val===!0},isBoolAttr=function(field){switch(field){case"allowfullscreen":case"allowpaymentrequest":case"async":case"autofocus":case"autoplay":case"checked":case"controls":case"default":case"defer":case"disabled":case"formnovalidate":case"hidden":case"ismap":case"itemscope":case"loop":case"multiple":case"muted":case"nomodule":case"novalidate":case"open":case"playsinline":case"readonly":case"required":case"reversed":case"selected":case"truespeed":case"webkitdirectory":return!0;default:return!1}};class BaseInterpreter{global;local;root;handler;resizeObserver;intersectionObserver;nodes;stack;templates;m;constructor(){}initialize(root,handler=null){this.global={},this.local={},this.root=root,this.nodes=[root],this.stack=[root],this.templates={},this.handler=handler}handleResizeEvent(entry){const target=entry.target;let event=new CustomEvent("resize",{bubbles:!1,detail:entry});target.dispatchEvent(event)}createResizeObserver(element){if(!this.resizeObserver)this.resizeObserver=new ResizeObserver((entries)=>{for(let entry of entries)this.handleResizeEvent(entry)});this.resizeObserver.observe(element)}removeResizeObserver(element){if(this.resizeObserver)this.resizeObserver.unobserve(element)}handleIntersectionEvent(entry){const target=entry.target;let event=new CustomEvent("visible",{bubbles:!1,detail:entry});target.dispatchEvent(event)}createIntersectionObserver(element){if(!this.intersectionObserver)this.intersectionObserver=new IntersectionObserver((entries)=>{for(let entry of entries)this.handleIntersectionEvent(entry)});this.intersectionObserver.observe(element)}removeIntersectionObserver(element){if(this.intersectionObserver)this.intersectionObserver.unobserve(element)}createListener(event_name,element,bubbles){if(event_name=="resize")this.createResizeObserver(element);else if(event_name=="visible")this.createIntersectionObserver(element);if(bubbles)if(this.global[event_name]===void 0)this.global[event_name]={active:1,callback:this.handler},this.root.addEventListener(event_name,this.handler);else this.global[event_name].active++;else{const id=element.getAttribute("data-dioxus-id");if(!this.local[id])this.local[id]={};element.addEventListener(event_name,this.handler)}}removeListener(element,event_name,bubbles){if(event_name=="resize")this.removeResizeObserver(element);else if(event_name=="visible")this.removeIntersectionObserver(element);else if(bubbles)this.removeBubblingListener(event_name);else this.removeNonBubblingListener(element,event_name)}removeBubblingListener(event_name){if(this.global[event_name].active--,this.global[event_name].active===0)this.root.removeEventListener(event_name,this.global[event_name].callback),delete this.global[event_name]}removeNonBubblingListener(element,event_name){const id=element.getAttribute("data-dioxus-id");if(delete this.local[id][event_name],Object.keys(this.local[id]).length===0)delete this.local[id];element.removeEventListener(event_name,this.handler)}removeAllNonBubblingListeners(element){const id=element.getAttribute("data-dioxus-id");delete this.local[id]}getNode(id){return this.nodes[id]}pushRoot(node){this.stack.push(node)}appendChildren(id,many){const root=this.nodes[id],els=this.stack.splice(this.stack.length-many);for(let k=0;k<many;k++)root.appendChild(els[k])}loadChild(ptr,len){let node=this.stack[this.stack.length-1],ptr_end=ptr+len;for(;ptr<ptr_end;ptr++){let end=this.m.getUint8(ptr);for(node=node.firstChild;end>0;end--)node=node.nextSibling}return node}saveTemplate(nodes,tmpl_id){this.templates[tmpl_id]=nodes}hydrate_node(hydrateNode,ids){const split=hydrateNode.getAttribute("data-node-hydration").split(","),id=ids[parseInt(split[0])];if(this.nodes[id]=hydrateNode,split.length>1){hydrateNode.listening=split.length-1,hydrateNode.setAttribute("data-dioxus-id",id.toString());for(let j=1;j<split.length;j++){const split2=split[j].split(":"),event_name=split2[0],bubbles=split2[1]==="1";this.createListener(event_name,hydrateNode,bubbles)}}}hydrate(ids,underNodes){for(let i=0;i<underNodes.length;i++){const under=underNodes[i];if(under instanceof HTMLElement){if(under.getAttribute("data-node-hydration"))this.hydrate_node(under,ids);const hydrateNodes=under.querySelectorAll("[data-node-hydration]");for(let i2=0;i2<hydrateNodes.length;i2++)this.hydrate_node(hydrateNodes[i2],ids)}const treeWalker=document.createTreeWalker(under,NodeFilter.SHOW_COMMENT);while(treeWalker.currentNode){const currentNode=treeWalker.currentNode;if(currentNode.nodeType===Node.COMMENT_NODE){const id=currentNode.textContent,placeholderSplit=id.split("placeholder");if(placeholderSplit.length>1){if(this.nodes[ids[parseInt(placeholderSplit[1])]]=currentNode,!treeWalker.nextNode())break;continue}const textNodeSplit=id.split("node-id");if(textNodeSplit.length>1){let next=currentNode.nextSibling;currentNode.remove();let commentAfterText,textNode;if(next.nodeType===Node.COMMENT_NODE){const newText=next.parentElement.insertBefore(document.createTextNode(""),next);commentAfterText=next,textNode=newText}else textNode=next,commentAfterText=textNode.nextSibling;treeWalker.currentNode=commentAfterText,this.nodes[ids[parseInt(textNodeSplit[1])]]=textNode;let exit=!treeWalker.nextNode();if(commentAfterText.remove(),exit)break;continue}}if(!treeWalker.nextNode())break}}}setAttributeInner(node,field,value,ns){setAttributeInner(node,field,value,ns)}}export{BaseInterpreter};
+function setAttributeInner(node,field,value,ns){if(ns==="style"){node.style.setProperty(field,value);return}if(ns){node.setAttributeNS(ns,field,value);return}switch(field){case"value":if(node.value!==value)node.value=value;break;case"initial_value":node.defaultValue=value;break;case"checked":node.checked=truthy(value);break;case"initial_checked":node.defaultChecked=truthy(value);break;case"selected":node.selected=truthy(value);break;case"initial_selected":node.defaultSelected=truthy(value);break;case"dangerous_inner_html":node.innerHTML=value;break;default:if(!truthy(value)&&isBoolAttr(field))node.removeAttribute(field);else node.setAttribute(field,value)}}var truthy=function(val){return val==="true"||val===!0},isBoolAttr=function(field){switch(field){case"allowfullscreen":case"allowpaymentrequest":case"async":case"autofocus":case"autoplay":case"checked":case"controls":case"default":case"defer":case"disabled":case"formnovalidate":case"hidden":case"ismap":case"itemscope":case"loop":case"multiple":case"muted":case"nomodule":case"novalidate":case"open":case"playsinline":case"readonly":case"required":case"reversed":case"selected":case"truespeed":case"webkitdirectory":return!0;default:return!1}};class BaseInterpreter{global;local;root;handler;resizeObserver;intersectionObserver;nodes;stack;templates;m;constructor(){}initialize(root,handler=null){this.global={},this.local={},this.root=root,this.nodes=[root],this.stack=[root],this.templates={},this.handler=handler,root.setAttribute("data-dioxus-id","0")}handleResizeEvent(entry){const target=entry.target;let event=new CustomEvent("resize",{bubbles:!1,detail:entry});target.dispatchEvent(event)}createResizeObserver(element){if(!this.resizeObserver)this.resizeObserver=new ResizeObserver((entries)=>{for(let entry of entries)this.handleResizeEvent(entry)});this.resizeObserver.observe(element)}removeResizeObserver(element){if(this.resizeObserver)this.resizeObserver.unobserve(element)}handleIntersectionEvent(entry){const target=entry.target;let event=new CustomEvent("visible",{bubbles:!1,detail:entry});target.dispatchEvent(event)}createIntersectionObserver(element){if(!this.intersectionObserver)this.intersectionObserver=new IntersectionObserver((entries)=>{for(let entry of entries)this.handleIntersectionEvent(entry)});this.intersectionObserver.observe(element)}removeIntersectionObserver(element){if(this.intersectionObserver)this.intersectionObserver.unobserve(element)}createListener(event_name,element,bubbles){if(event_name=="resize")this.createResizeObserver(element);else if(event_name=="visible")this.createIntersectionObserver(element);if(bubbles)if(this.global[event_name]===void 0)this.global[event_name]={active:1,callback:this.handler},this.root.addEventListener(event_name,this.handler);else this.global[event_name].active++;else{const id=element.getAttribute("data-dioxus-id");if(!this.local[id])this.local[id]={};element.addEventListener(event_name,this.handler)}}removeListener(element,event_name,bubbles){if(event_name=="resize")this.removeResizeObserver(element);else if(event_name=="visible")this.removeIntersectionObserver(element);else if(bubbles)this.removeBubblingListener(event_name);else this.removeNonBubblingListener(element,event_name)}removeBubblingListener(event_name){if(this.global[event_name].active--,this.global[event_name].active===0)this.root.removeEventListener(event_name,this.global[event_name].callback),delete this.global[event_name]}removeNonBubblingListener(element,event_name){const id=element.getAttribute("data-dioxus-id");if(delete this.local[id][event_name],Object.keys(this.local[id]).length===0)delete this.local[id];element.removeEventListener(event_name,this.handler)}removeAllNonBubblingListeners(element){const id=element.getAttribute("data-dioxus-id");delete this.local[id]}getNode(id){return this.nodes[id]}pushRoot(node){this.stack.push(node)}appendChildren(id,many){const root=this.nodes[id],els=this.stack.splice(this.stack.length-many);for(let k=0;k<many;k++)root.appendChild(els[k])}loadChild(ptr,len){let node=this.stack[this.stack.length-1],ptr_end=ptr+len;for(;ptr<ptr_end;ptr++){let end=this.m.getUint8(ptr);for(node=node.firstChild;end>0;end--)node=node.nextSibling}return node}saveTemplate(nodes,tmpl_id){this.templates[tmpl_id]=nodes}hydrate_node(hydrateNode,ids){const split=hydrateNode.getAttribute("data-node-hydration").split(","),id=ids[parseInt(split[0])];if(this.nodes[id]=hydrateNode,split.length>1){hydrateNode.listening=split.length-1,hydrateNode.setAttribute("data-dioxus-id",id.toString());for(let j=1;j<split.length;j++){const split2=split[j].split(":"),event_name=split2[0],bubbles=split2[1]==="1";this.createListener(event_name,hydrateNode,bubbles)}}}hydrate(ids,underNodes){for(let i=0;i<underNodes.length;i++){const under=underNodes[i];if(under instanceof HTMLElement){if(under.getAttribute("data-node-hydration"))this.hydrate_node(under,ids);const hydrateNodes=under.querySelectorAll("[data-node-hydration]");for(let i2=0;i2<hydrateNodes.length;i2++)this.hydrate_node(hydrateNodes[i2],ids)}const treeWalker=document.createTreeWalker(under,NodeFilter.SHOW_COMMENT);while(treeWalker.currentNode){const currentNode=treeWalker.currentNode;if(currentNode.nodeType===Node.COMMENT_NODE){const id=currentNode.textContent,placeholderSplit=id.split("placeholder");if(placeholderSplit.length>1){if(this.nodes[ids[parseInt(placeholderSplit[1])]]=currentNode,!treeWalker.nextNode())break;continue}const textNodeSplit=id.split("node-id");if(textNodeSplit.length>1){let next=currentNode.nextSibling;currentNode.remove();let commentAfterText,textNode;if(next.nodeType===Node.COMMENT_NODE){const newText=next.parentElement.insertBefore(document.createTextNode(""),next);commentAfterText=next,textNode=newText}else textNode=next,commentAfterText=textNode.nextSibling;treeWalker.currentNode=commentAfterText,this.nodes[ids[parseInt(textNodeSplit[1])]]=textNode;let exit=!treeWalker.nextNode();if(commentAfterText.remove(),exit)break;continue}}if(!treeWalker.nextNode())break}}}setAttributeInner(node,field,value,ns){setAttributeInner(node,field,value,ns)}}export{BaseInterpreter};

+ 1 - 1
packages/interpreter/src/js/hash.txt

@@ -1 +1 @@
-[6449103750905854967, 5429983586723452597, 13069001215487072322, 8716623267269178440, 5336385715226370016, 14456089431355876478, 7422899642446454418, 5052021921702764563, 12925655762638175824, 5638004933879392817]
+[6449103750905854967, 3846442265490457921, 13069001215487072322, 8716623267269178440, 5336385715226370016, 14456089431355876478, 7422899642446454418, 5052021921702764563, 12925655762638175824, 5638004933879392817]

+ 4 - 1
packages/interpreter/src/ts/core.ts

@@ -31,7 +31,7 @@ export class BaseInterpreter {
   // sledgehammer is generating this...
   m: any;
 
-  constructor() {}
+  constructor() { }
 
   initialize(root: HTMLElement, handler: EventListener | null = null) {
     this.global = {};
@@ -43,6 +43,9 @@ export class BaseInterpreter {
     this.templates = {};
 
     this.handler = handler;
+
+    // make sure to set the root element's ID so it still registers events
+    root.setAttribute('data-dioxus-id', "0");
   }
 
   handleResizeEvent(entry: ResizeObserverEntry) {

+ 25 - 0
packages/logger/Cargo.toml

@@ -0,0 +1,25 @@
+[package]
+name = "dioxus-logger"
+version = { workspace = true }
+edition = "2021"
+description = "A logging utility to provide a standard interface whether you're targetting web desktop, fullstack, and more."
+authors = ["DogeDark", "Jonathan Kelley"]
+repository = "https://github.com/dioxuslabs/dioxus"
+homepage = "https://github.com/dioxuslabs/dioxus"
+readme = "README.md"
+license = "MIT"
+keywords = ["dioxus", "log", "logging"]
+categories = ["development-tools::debugging"]
+
+
+[dependencies]
+dioxus-cli-config = { workspace =  true }
+tracing = { workspace = true }
+tracing-subscriber = { workspace = true, features = ["registry", "std"] }
+
+[target.'cfg(target_arch = "wasm32")'.dependencies]
+tracing-wasm = { workspace = true }
+console_error_panic_hook = { workspace = true }
+
+[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
+tracing-subscriber = { workspace = true, features = [ "fmt" ] }

+ 110 - 0
packages/logger/src/lib.rs

@@ -0,0 +1,110 @@
+use tracing::{
+    subscriber::{set_global_default, SetGlobalDefaultError},
+    Level,
+};
+
+pub use tracing;
+
+/// Attempt to initialize the subscriber if it doesn't already exist, with default settings.
+///
+/// See [`crate::init`] for more info.
+///
+/// If you're doing setup before your `dioxus::launch` function that requires lots of logging, then
+/// it might be worth calling this earlier than launch.
+///
+/// `dioxus::launch` calls this for you automatically and won't replace any facade you've already set.
+///
+/// # Example
+///
+/// ```rust,no_run
+/// use dioxus::prelude::*;
+/// use tracing::info;
+///
+/// fn main() {
+///     dioxus::logger::initialize_default();
+///
+///     info!("Doing some work before launching...");
+///
+///     dioxus::launch(App);
+/// }
+///
+/// #[component]
+/// fn App() -> Element {
+///     info!("App rendered");
+///     rsx! {
+///         p { "hi" }
+///     }
+/// }
+/// ```
+pub fn initialize_default() {
+    if tracing::dispatcher::has_been_set() {
+        return;
+    }
+
+    if cfg!(debug_assertions) {
+        _ = init(Level::DEBUG);
+    } else {
+        _ = init(Level::INFO);
+    }
+}
+
+/// Initialize `dioxus-logger` with a specified max filter.
+///
+/// Generally it is best to initialize the logger before launching your Dioxus app.
+/// Works on Web, Desktop, Fullstack, and Liveview.
+///
+/// # Example
+///
+/// ```rust,no_run
+/// use dioxus::prelude::*;
+/// use dioxus::logger::tracing::{Level, info};
+///
+/// fn main() {
+///     dioxus::logger::init(Level::INFO).expect("logger failed to init");
+///     dioxus::launch(App);
+/// }
+///
+/// #[component]
+/// fn App() -> Element {
+///     info!("App rendered");
+///     rsx! {
+///         p { "hi" }
+///     }
+/// }
+/// ```
+pub fn init(level: Level) -> Result<(), SetGlobalDefaultError> {
+    /*
+    The default logger is currently set to log in fmt mode (meaning print directly to stdout)
+
+    Eventually we want to change the output mode to be `json` when running under `dx`. This would let
+    use re-format the tracing spans to be better integrated with `dx`
+    */
+
+    #[cfg(target_arch = "wasm32")]
+    {
+        use tracing_subscriber::layer::SubscriberExt;
+        use tracing_subscriber::Registry;
+
+        let layer_config = tracing_wasm::WASMLayerConfigBuilder::new()
+            .set_max_level(level)
+            .build();
+        let layer = tracing_wasm::WASMLayer::new(layer_config);
+        let reg = Registry::default().with(layer);
+
+        console_error_panic_hook::set_once();
+        set_global_default(reg)
+    }
+
+    #[cfg(not(target_arch = "wasm32"))]
+    {
+        let sub = tracing_subscriber::FmtSubscriber::builder().with_max_level(level);
+
+        if !dioxus_cli_config::is_cli_enabled() {
+            return set_global_default(sub.finish());
+        }
+
+        // todo(jon): this is a small hack to clean up logging when running under the CLI
+        // eventually we want to emit everything as json and let the CLI manage the parsing + display
+        set_global_default(sub.without_time().with_target(false).finish())
+    }
+}

+ 3 - 4
packages/signals/Cargo.toml

@@ -16,9 +16,9 @@ rust-version = "1.79.0"
 dioxus-core = { workspace = true }
 generational-box = { workspace = true }
 tracing = { workspace = true }
-serde = { version = "1", features = ["derive"], optional = true }
+serde = { workspace = true, features = ["derive"], optional = true }
 parking_lot = "0.12.1"
-once_cell = "1.18.0"
+once_cell = { workspace = true }
 rustc-hash = { workspace = true }
 futures-channel = { workspace = true }
 futures-util = { workspace = true }
@@ -27,8 +27,7 @@ warnings = { workspace = true }
 [dev-dependencies]
 dioxus = { workspace = true }
 tokio = { workspace = true, features = ["full"] }
-tracing-subscriber = "0.3.17"
-simple_logger = "4.2.0"
+tracing-subscriber = { workspace = true, default-features = true }
 reqwest = { workspace = true }
 rand = { workspace = true }
 

+ 1 - 3
packages/signals/tests/memo.rs

@@ -11,7 +11,7 @@ use std::sync::atomic::{AtomicBool, Ordering};
 
 #[test]
 fn memos_rerun() {
-    let _ = simple_logger::SimpleLogger::new().init();
+    tracing_subscriber::fmt::init();
 
     #[derive(Default)]
     struct RunCounter {
@@ -53,8 +53,6 @@ fn memos_rerun() {
 
 #[test]
 fn memos_prevents_component_rerun() {
-    let _ = simple_logger::SimpleLogger::new().init();
-
     #[derive(Default)]
     struct RunCounter {
         component: usize,

+ 1 - 1
packages/signals/tests/subscribe.rs

@@ -11,7 +11,7 @@ use std::cell::RefCell;
 
 #[test]
 fn reading_subscribes() {
-    simple_logger::SimpleLogger::new().init().unwrap();
+    tracing_subscriber::fmt::init();
 
     #[derive(Default)]
     struct RunCounter {

+ 1 - 3
packages/web/Cargo.toml

@@ -29,7 +29,6 @@ wasm-bindgen = { workspace = true }
 wasm-bindgen-futures = "0.4.29"
 tracing = { workspace = true }
 rustc-hash = { workspace = true }
-console_error_panic_hook = { version = "0.1.7", optional = true }
 futures-util = { workspace = true, features = [
     "std",
     "async-await",
@@ -85,8 +84,7 @@ features = [
 lazy-js-bundle = { workspace = true }
 
 [features]
-default = ["panic_hook", "mounted", "file_engine", "devtools", "document"]
-panic_hook = ["dep:console_error_panic_hook"]
+default = ["mounted", "file_engine", "devtools", "document"]
 hydrate = ["web-sys/Comment", "ciborium", "dep:serde"]
 mounted = [
     "web-sys/Element",

+ 0 - 10
packages/web/src/cfg.rs

@@ -13,7 +13,6 @@ use wasm_bindgen::JsCast as _;
 pub struct Config {
     pub(crate) hydrate: bool,
     pub(crate) root: ConfigRoot,
-    pub(crate) default_panic_hook: bool,
 }
 
 impl LaunchConfig for Config {}
@@ -68,14 +67,6 @@ impl Config {
         self.root = ConfigRoot::RootNode(node);
         self
     }
-
-    /// Set whether or not Dioxus should use the built-in panic hook or defer to your own.
-    ///
-    /// The panic hook is set to true normally so even the simplest apps have helpful error messages.
-    pub fn with_default_panic_hook(mut self, f: bool) -> Self {
-        self.default_panic_hook = f;
-        self
-    }
 }
 
 impl Default for Config {
@@ -83,7 +74,6 @@ impl Default for Config {
         Self {
             hydrate: false,
             root: ConfigRoot::RootName("main".to_string()),
-            default_panic_hook: true,
         }
     }
 }

+ 0 - 5
packages/web/src/lib.rs

@@ -66,11 +66,6 @@ pub async fn run(mut virtual_dom: VirtualDom, web_config: Config) -> ! {
     #[cfg(feature = "document")]
     virtual_dom.in_runtime(document::init_document);
 
-    #[cfg(feature = "panic_hook")]
-    if web_config.default_panic_hook {
-        console_error_panic_hook::set_once();
-    }
-
     #[cfg(all(feature = "devtools", debug_assertions))]
     let mut hotreload_rx = devtools::init();