Browse Source

integrate liveview with the launch builder

Evan Almloff 1 year ago
parent
commit
636aeb4b90

+ 1 - 1
Cargo.lock

@@ -2323,7 +2323,6 @@ dependencies = [
  "dioxus-liveview",
  "dioxus-mobile",
  "dioxus-router",
- "dioxus-rsx",
  "dioxus-signals",
  "dioxus-ssr",
  "dioxus-tui",
@@ -2693,6 +2692,7 @@ dependencies = [
  "async-trait",
  "axum 0.6.20",
  "dioxus",
+ "dioxus-cli-config",
  "dioxus-core",
  "dioxus-hot-reload",
  "dioxus-html",

+ 6 - 0
Cargo.toml

@@ -145,6 +145,12 @@ tokio = { version = "1.16.1", features = ["full"] }
 # To make most examples faster to compile, we split out assets and http-related stuff
 # This trims off like 270 dependencies, leading to a significant speedup in compilation time
 [features]
+liveview = ["dioxus/liveview"]
+fullstack = ["dioxus/fullstack"]
+axum = ["dioxus/axum"]
+salvo = ["dioxus/salvo"]
+rocket = ["dioxus/rocket"]
+server = ["dioxus/server"]
 default = ["dioxus/desktop"]
 web = ["dioxus/web"]
 collect-assets = ["manganis"]

+ 4 - 4
packages/cli/src/cli/cfg.rs

@@ -45,8 +45,8 @@ pub struct ConfigOptsBuild {
     #[clap(long, default_value_t = { "web".to_string() })]
     pub client_feature: String,
 
-    /// The feature to use for the server in a fullstack app [default: "ssr"]
-    #[clap(long, default_value_t = { "ssr".to_string() })]
+    /// The feature to use for the server in a fullstack app [default: "server"]
+    #[clap(long, default_value_t = { "server".to_string() })]
     pub server_feature: String,
 
     /// Rustc platform triple
@@ -140,8 +140,8 @@ pub struct ConfigOptsServe {
     #[clap(long, default_value_t = { "web".to_string() })]
     pub client_feature: String,
 
-    /// The feature to use for the server in a fullstack app [default: "ssr"]
-    #[clap(long, default_value_t = { "ssr".to_string() })]
+    /// The feature to use for the server in a fullstack app [default: "server"]
+    #[clap(long, default_value_t = { "server".to_string() })]
     pub server_feature: String,
 
     /// Rustc platform triple

+ 5 - 5
packages/dioxus/Cargo.toml

@@ -16,7 +16,6 @@ dioxus-html = { workspace = true, optional = true }
 dioxus-core-macro = { workspace = true, optional = true }
 dioxus-config-macro = { workspace = true, optional = true }
 dioxus-hooks = { workspace = true, optional = true }
-dioxus-rsx = { workspace = true, optional = true }
 dioxus-signals = { workspace = true, optional = true }
 dioxus-router = { workspace = true, optional = true }
 dioxus-web = { workspace = true, optional = true }
@@ -35,7 +34,7 @@ dioxus-hot-reload = { workspace = true, optional = true }
 [features]
 default = ["macro", "html", "hot-reload", "signals", "hooks", "launch"]
 signals = ["dioxus-signals"]
-macro = ["dioxus-core-macro", "dioxus-rsx"]
+macro = ["dioxus-core-macro"]
 html = ["dioxus-html"]
 hooks = ["dioxus-hooks"]
 hot-reload = ["dioxus-hot-reload"]
@@ -51,9 +50,10 @@ web = ["dioxus-web", "dioxus-fullstack?/web", "dioxus-config-macro/web", "dioxus
 server = ["dioxus-fullstack?/ssr", "dioxus-config-macro/ssr", "dioxus-router?/ssr"]
 ssr = ["dioxus-ssr"]
 liveview = ["dioxus-liveview", "dioxus-config-macro/liveview", "dioxus-router?/liveview"]
-axum = ["dioxus-fullstack?/axum"]
-salvo = ["dioxus-fullstack?/salvo"]
-warp = ["dioxus-fullstack?/warp"]
+axum = ["dioxus-fullstack?/axum", "dioxus-liveview?/axum"]
+salvo = ["dioxus-fullstack?/salvo", "dioxus-liveview?/salvo"]
+warp = ["dioxus-fullstack?/warp", "dioxus-liveview?/warp"]
+rocket = ["dioxus-liveview?/rocket"]
 tui = ["dioxus-tui", "dioxus-config-macro/tui"]
 
 [dev-dependencies]

+ 17 - 4
packages/dioxus/src/launch.rs

@@ -17,10 +17,10 @@ pub struct LaunchBuilder<Cfg: 'static = (), ContextFn: ?Sized = ValidContext> {
 
 pub type LaunchFn<Cfg, Context> = fn(fn() -> Element, Vec<Box<Context>>, Cfg);
 
-#[cfg(feature = "fullstack")]
+#[cfg(any(feature = "fullstack", feature = "liveview"))]
 type ValidContext = SendContext;
 
-#[cfg(not(feature = "fullstack"))]
+#[cfg(not(any(feature = "fullstack", feature = "liveview")))]
 type ValidContext = UnsendContext;
 
 type SendContext = dyn Fn() -> Box<dyn Any> + Send + Sync + 'static;
@@ -154,12 +154,24 @@ mod current_platform {
     pub use dioxus_web::launch::*;
 
     #[cfg(all(
-        feature = "tui",
+        feature = "liveview",
         not(any(feature = "web", feature = "desktop", feature = "fullstack"))
     ))]
+    pub use dioxus_liveview::launch::*;
+
+    #[cfg(all(
+        feature = "tui",
+        not(any(
+            feature = "liveview",
+            feature = "web",
+            feature = "desktop",
+            feature = "fullstack"
+        ))
+    ))]
     pub use dioxus_tui::launch::*;
 
     #[cfg(not(any(
+        feature = "liveview",
         feature = "desktop",
         feature = "web",
         feature = "tui",
@@ -168,6 +180,7 @@ mod current_platform {
     pub type Config = ();
 
     #[cfg(not(any(
+        feature = "liveview",
         feature = "desktop",
         feature = "web",
         feature = "tui",
@@ -176,7 +189,7 @@ mod current_platform {
     pub fn launch(
         root: fn() -> dioxus_core::Element,
         contexts: Vec<Box<super::ValidContext>>,
-        platform_config: Config,
+        platform_config: (),
     ) {
     }
 }

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

@@ -21,9 +21,6 @@ pub mod events {
 #[cfg(feature = "html")]
 pub use dioxus_html as html;
 
-#[cfg(feature = "macro")]
-pub use dioxus_rsx as rsx;
-
 #[cfg(feature = "macro")]
 pub use dioxus_core_macro as core_macro;
 

+ 2 - 1
packages/liveview/Cargo.toml

@@ -27,6 +27,7 @@ rustc-hash = { workspace = true }
 dioxus-core = { workspace = true, features = ["serialize"] }
 dioxus-interpreter-js = { workspace = true, features = ["binary-protocol"] }
 dioxus-hot-reload = { workspace = true, optional = true }
+dioxus-cli-config = { workspace = true }
 
 # warp
 warp = { version = "0.3.3", optional = true }
@@ -35,7 +36,7 @@ warp = { version = "0.3.3", optional = true }
 axum = { version = "0.6.1", optional = true, features = ["ws"] }
 
 # salvo
-salvo = { version = "0.63.0", optional = true, features = ["websocket"] }
+salvo = { version = "0.63.0", optional = true, features = ["websocket", "affix"] }
 once_cell = "1.17.1"
 async-trait = "0.1.71"
 

+ 3 - 39
packages/liveview/examples/axum.rs

@@ -1,5 +1,6 @@
-use axum::{extract::ws::WebSocketUpgrade, response::Html, routing::get, Router};
+use axum::Router;
 use dioxus::prelude::*;
+use dioxus_liveview::LiveviewRouter;
 
 fn app() -> Element {
     let mut num = use_signal(|| 0);
@@ -18,44 +19,7 @@ async fn main() {
 
     let addr: std::net::SocketAddr = ([127, 0, 0, 1], 3030).into();
 
-    let view = dioxus_liveview::LiveViewPool::new();
-    let index_page_with_glue = |glue: &str| {
-        Html(format!(
-            r#"
-        <!DOCTYPE html>
-        <html>
-            <head> <title>Dioxus LiveView with axum</title>  </head>
-            <body> <div id="main"></div> </body>
-            {glue}
-        </html>
-        "#,
-        ))
-    };
-
-    let app =
-        Router::new()
-            .route(
-                "/",
-                get(move || async move {
-                    index_page_with_glue(&dioxus_liveview::interpreter_glue(&format!(
-                        "ws://{addr}/ws"
-                    )))
-                }),
-            )
-            .route(
-                "/as-path",
-                get(move || async move {
-                    index_page_with_glue(&dioxus_liveview::interpreter_glue("/ws"))
-                }),
-            )
-            .route(
-                "/ws",
-                get(move |ws: WebSocketUpgrade| async move {
-                    ws.on_upgrade(move |socket| async move {
-                        _ = view.launch(dioxus_liveview::axum_socket(socket), app).await;
-                    })
-                }),
-            );
+    let app = Router::new().with_app("/", app);
 
     println!("Listening on http://{addr}");
 

+ 1 - 1
packages/liveview/examples/salvo.rs

@@ -36,7 +36,7 @@ async fn main() {
 }
 
 #[handler]
-fn index(_depot: &mut Depot, res: &mut Response) {
+fn index(res: &mut Response) {
     let addr: SocketAddr = ([127, 0, 0, 1], 3030).into();
     res.render(Text::Html(format!(
         r#"

+ 1 - 1
packages/liveview/examples/warp.rs

@@ -1,5 +1,5 @@
 use dioxus::prelude::*;
-use dioxus_liveview::adapters::warp_adapter::warp_socket;
+use dioxus_liveview::warp_adapter::warp_socket;
 use dioxus_liveview::LiveViewPool;
 use std::net::SocketAddr;
 use warp::ws::Ws;

+ 69 - 2
packages/liveview/src/adapters/axum_adapter.rs

@@ -1,5 +1,15 @@
-use crate::{LiveViewError, LiveViewSocket};
-use axum::extract::ws::{Message, WebSocket};
+use std::sync::Arc;
+
+use crate::{interpreter_glue, LiveViewError, LiveViewSocket, LiveviewRouter};
+use axum::{
+    extract::{
+        ws::{Message, WebSocket},
+        WebSocketUpgrade,
+    },
+    response::Html,
+    routing::*,
+    Router,
+};
 use futures_util::{SinkExt, StreamExt};
 
 /// Convert a warp websocket into a LiveViewSocket
@@ -22,3 +32,60 @@ fn transform_rx(message: Result<Message, axum::Error>) -> Result<Vec<u8>, LiveVi
 async fn transform_tx(message: Vec<u8>) -> Result<Message, axum::Error> {
     Ok(Message::Binary(message))
 }
+
+impl LiveviewRouter for Router {
+    fn create_default_liveview_router() -> Self {
+        Router::new()
+    }
+
+    fn with_virtual_dom(
+        self,
+        route: &str,
+        app: impl Fn() -> dioxus_core::prelude::VirtualDom + Send + Sync + 'static,
+    ) -> Self {
+        let view = crate::LiveViewPool::new();
+
+        let ws_path = format!("{}/ws", route);
+        let title = crate::app_title();
+
+        let index_page_with_glue = move |glue: &str| {
+            Html(format!(
+                r#"
+        <!DOCTYPE html>
+        <html>
+            <head> <title>{title}</title>  </head>
+            <body> <div id="main"></div> </body>
+            {glue}
+        </html>
+        "#,
+            ))
+        };
+
+        let app = Arc::new(app);
+
+        self.route(
+            &ws_path,
+            get(move |ws: WebSocketUpgrade| async move {
+                let app = app.clone();
+                ws.on_upgrade(move |socket| async move {
+                    _ = view
+                        .launch_virtualdom(axum_socket(socket), move || app())
+                        .await;
+                })
+            }),
+        )
+        .route(
+            route,
+            get(move || async move { index_page_with_glue(&interpreter_glue(&ws_path)) }),
+        )
+    }
+
+    async fn start(self, address: impl Into<std::net::SocketAddr>) {
+        if let Err(err) = axum::Server::bind(&address.into())
+            .serve(self.into_make_service())
+            .await
+        {
+            eprintln!("Failed to start axum server: {}", err);
+        }
+    }
+}

+ 47 - 0
packages/liveview/src/adapters/mod.rs

@@ -0,0 +1,47 @@
+use std::future::Future;
+
+use dioxus_core::{Element, VirtualDom};
+
+#[cfg(feature = "warp")]
+pub mod warp_adapter;
+#[cfg(feature = "warp")]
+pub use warp_adapter::*;
+
+#[cfg(feature = "axum")]
+pub mod axum_adapter;
+#[cfg(feature = "axum")]
+pub use axum_adapter::*;
+
+#[cfg(feature = "salvo")]
+pub mod salvo_adapter;
+#[cfg(feature = "salvo")]
+pub use salvo_adapter::*;
+
+#[cfg(feature = "rocket")]
+pub mod rocket_adapter;
+#[cfg(feature = "rocket")]
+pub use rocket_adapter::*;
+
+/// A trait for servers that can be used to host a LiveView app.
+pub trait LiveviewRouter {
+    /// Create a new router.
+    fn create_default_liveview_router() -> Self;
+
+    /// Add a liveview route to the server from a component
+    fn with_app(self, route: &str, app: fn() -> Element) -> Self
+    where
+        Self: Sized,
+    {
+        self.with_virtual_dom(route, move || VirtualDom::new(app))
+    }
+
+    /// Add a liveview route to the server from a virtual dom.
+    fn with_virtual_dom(
+        self,
+        route: &str,
+        app: impl Fn() -> VirtualDom + Send + Sync + 'static,
+    ) -> Self;
+
+    /// Start the server on an address.
+    fn start(self, address: impl Into<std::net::SocketAddr>) -> impl Future<Output = ()>;
+}

+ 89 - 1
packages/liveview/src/adapters/rocket_adapter.rs

@@ -1,6 +1,13 @@
+use crate::LiveViewPool;
+use crate::LiveviewRouter;
 use crate::{LiveViewError, LiveViewSocket};
 use rocket::futures::{SinkExt, StreamExt};
+use rocket::response::content::RawHtml;
+use rocket::{get, routes, State};
+use rocket_ws::Channel;
+use rocket_ws::WebSocket;
 use rocket_ws::{result::Error, stream::DuplexStream, Message};
+use std::sync::Arc;
 
 /// Convert a rocket websocket into a LiveViewSocket
 ///
@@ -21,5 +28,86 @@ fn transform_rx(message: Result<Message, Error>) -> Result<Vec<u8>, LiveViewErro
 }
 
 async fn transform_tx(message: Vec<u8>) -> Result<Message, Error> {
-    Ok(Message::Text(String::from_utf8_lossy(&message).to_string()))
+    Ok(Message::Binary(message))
+}
+
+impl LiveviewRouter for rocket::Rocket<rocket::Build> {
+    fn create_default_liveview_router() -> Self {
+        Self::build()
+    }
+
+    fn with_virtual_dom(
+        self,
+        route: &str,
+        app: impl Fn() -> dioxus_core::prelude::VirtualDom + Send + Sync + 'static,
+    ) -> Self {
+        #[get("/")]
+        async fn index(request: &rocket::route::Route) -> RawHtml<String> {
+            let route = request.uri.base();
+
+            let glue = crate::interpreter_glue(&format!("{route}/ws",));
+
+            let title = crate::app_title();
+
+            RawHtml(format!(
+                r#"
+        <!DOCTYPE html>
+        <html>
+            <head> <title>{title}</title>  </head>
+            <body> <div id="main"></div> </body>
+            {glue}
+        </html>
+        "#
+            ))
+        }
+
+        #[get("/ws")]
+        fn ws(ws: WebSocket, app: &State<LiveviewApp>) -> Channel<'static> {
+            let app = app.inner();
+            let pool = app.pool.clone();
+            let app = app.app.clone();
+
+            ws.channel(move |stream| {
+                Box::pin(async move {
+                    let _ = pool
+                        .launch_virtualdom(crate::rocket_socket(stream), move || app())
+                        .await;
+                    Ok(())
+                })
+            })
+        }
+
+        struct LiveviewApp {
+            app: Arc<dyn Fn() -> dioxus_core::prelude::VirtualDom + Send + Sync + 'static>,
+            pool: LiveViewPool,
+        }
+
+        let app = Arc::new(app);
+
+        let view = crate::LiveViewPool::new();
+
+        self.manage(LiveviewApp {
+            app: app,
+            pool: view,
+        })
+        .mount(route, routes![index, ws])
+    }
+
+    async fn start(self, address: impl Into<std::net::SocketAddr>) {
+        let address = address.into();
+
+        let figment = self
+            .figment()
+            .clone()
+            .merge((rocket::Config::PORT, address.port()))
+            .merge((rocket::Config::ADDRESS, address.ip()));
+
+        self.configure(figment)
+            .ignite()
+            .await
+            .expect("Failed to ignite rocket")
+            .launch()
+            .await
+            .expect("Failed to launch rocket");
+    }
 }

+ 89 - 4
packages/liveview/src/adapters/salvo_adapter.rs

@@ -1,7 +1,16 @@
-use futures_util::{SinkExt, StreamExt};
-use salvo::ws::{Message, WebSocket};
-
+use crate::LiveViewPool;
+use crate::LiveviewRouter;
 use crate::{LiveViewError, LiveViewSocket};
+use futures_util::{SinkExt, StreamExt};
+use salvo::conn::TcpListener;
+use salvo::http::StatusError;
+use salvo::websocket::WebSocketUpgrade;
+use salvo::websocket::{Message, WebSocket};
+use salvo::writing::Text;
+use salvo::Listener;
+use salvo::Server;
+use salvo::{handler, Depot, Request, Response, Router};
+use std::sync::Arc;
 
 /// Convert a salvo websocket into a LiveViewSocket
 ///
@@ -19,5 +28,81 @@ fn transform_rx(message: Result<Message, salvo::Error>) -> Result<Vec<u8>, LiveV
 }
 
 async fn transform_tx(message: Vec<u8>) -> Result<Message, salvo::Error> {
-    Ok(Message::text(String::from_utf8_lossy(&message).to_string()))
+    Ok(Message::binary(message))
+}
+
+#[derive(Clone)]
+struct LiveviewApp {
+    app: Arc<dyn Fn() -> dioxus_core::prelude::VirtualDom + Send + Sync + 'static>,
+    pool: Arc<LiveViewPool>,
+}
+
+impl LiveviewRouter for Router {
+    fn create_default_liveview_router() -> Self {
+        Self::new()
+    }
+
+    fn with_virtual_dom(
+        self,
+        route: &str,
+        app: impl Fn() -> dioxus_core::prelude::VirtualDom + Send + Sync + 'static,
+    ) -> Self {
+        let app = Arc::new(app);
+
+        let view = crate::LiveViewPool::new();
+
+        self.push(
+            Router::with_path(route)
+                .hoop(salvo::affix::inject(LiveviewApp {
+                    app: app,
+                    pool: Arc::new(view),
+                }))
+                .get(index)
+                .push(Router::with_path("ws").get(connect)),
+        )
+    }
+
+    async fn start(self, address: impl Into<std::net::SocketAddr>) {
+        let address = address.into();
+
+        let acceptor = TcpListener::new(address).bind().await;
+        Server::new(acceptor).serve(self).await;
+    }
+}
+
+#[handler]
+fn index(req: &mut Request, res: &mut Response) {
+    let base = req.uri().path();
+    let title = crate::app_title();
+
+    res.render(Text::Html(format!(
+        r#"
+            <!DOCTYPE html>
+            <html>
+                <head> <title>{title}</title>  </head>
+                <body> <div id="main"></div> </body>
+                {glue}
+            </html>
+            "#,
+        glue = crate::interpreter_glue(&format!("{base}/ws"))
+    )));
+}
+
+#[handler]
+async fn connect(
+    req: &mut Request,
+    depot: &mut Depot,
+    res: &mut Response,
+) -> Result<(), StatusError> {
+    let app = depot.obtain::<LiveviewApp>().unwrap().clone();
+    let view = app.pool.clone();
+    let app = app.app.clone();
+
+    WebSocketUpgrade::new()
+        .upgrade(req, res, |ws| async move {
+            _ = view
+                .launch_virtualdom(crate::salvo_socket(ws), move || app())
+                .await;
+        })
+        .await
 }

+ 1 - 1
packages/liveview/src/adapters/warp_adapter.rs

@@ -21,5 +21,5 @@ fn transform_rx(message: Result<Message, warp::Error>) -> Result<Vec<u8>, LiveVi
 }
 
 async fn transform_tx(message: Vec<u8>) -> Result<Message, warp::Error> {
-    Ok(Message::text(String::from_utf8_lossy(&message).to_string()))
+    Ok(Message::binary(message))
 }

+ 63 - 0
packages/liveview/src/config.rs

@@ -0,0 +1,63 @@
+use dioxus_cli_config::CURRENT_CONFIG;
+use dioxus_core::VirtualDom;
+
+use crate::LiveviewRouter;
+
+pub(crate) fn app_title() -> String {
+    CURRENT_CONFIG
+        .as_ref()
+        .map(|c| c.dioxus_config.web.app.title.clone())
+        .unwrap_or_else(|_| "Dioxus Liveview App".to_string())
+}
+
+/// A configuration for the LiveView server.
+pub struct Config<R: LiveviewRouter> {
+    router: R,
+    address: std::net::SocketAddr,
+    route: String,
+}
+
+impl<R: LiveviewRouter> Default for Config<R> {
+    fn default() -> Self {
+        Self {
+            router: R::create_default_liveview_router(),
+            address: ([127, 0, 0, 1], 8080).into(),
+            route: "/".to_string(),
+        }
+    }
+}
+
+impl<R: LiveviewRouter> Config<R> {
+    /// Set the route to use for the LiveView server.
+    pub fn route(mut self, route: impl Into<String>) -> Self {
+        self.route = route.into();
+        self
+    }
+
+    /// Create a new configuration for the LiveView server.
+    pub fn with_app(mut self, app: fn() -> dioxus_core::prelude::Element) -> Self {
+        self.router = self.router.with_app(&self.route, app);
+        self
+    }
+
+    /// Create a new configuration for the LiveView server.
+    pub fn with_virtual_dom(
+        mut self,
+        virtual_dom: impl Fn() -> VirtualDom + Send + Sync + 'static,
+    ) -> Self {
+        self.router = self.router.with_virtual_dom(&self.route, virtual_dom);
+        self
+    }
+
+    /// Set the address to listen on.
+    pub fn address(mut self, address: impl Into<std::net::SocketAddr>) -> Self {
+        self.address = address.into();
+        self
+    }
+
+    /// Launch the LiveView server.
+    pub async fn launch(self) {
+        println!("{} started on http://{}", app_title(), self.address);
+        self.router.start(self.address).await
+    }
+}

+ 35 - 0
packages/liveview/src/launch.rs

@@ -0,0 +1,35 @@
+use dioxus_core::*;
+use std::any::Any;
+
+#[cfg(feature = "axum")]
+pub type Config = crate::Config<axum::Router>;
+#[cfg(feature = "salvo")]
+pub type Config = crate::Config<salvo::Router>;
+#[cfg(feature = "rocket")]
+pub type Config = crate::Config<rocket::Rocket<rocket::Build>>;
+
+/// Launches the WebView and runs the event loop, with configuration and root props.
+pub fn launch(
+    root: fn() -> Element,
+    contexts: Vec<Box<dyn Fn() -> Box<dyn Any> + Send + Sync>>,
+    platform_config: Config,
+) {
+    tokio::runtime::Builder::new_multi_thread()
+        .enable_all()
+        .build()
+        .unwrap()
+        .block_on(async move {
+            platform_config
+                .with_virtual_dom(move || {
+                    let mut virtual_dom = VirtualDom::new(root);
+
+                    for context in &contexts {
+                        virtual_dom.insert_any_root_context(context());
+                    }
+
+                    virtual_dom
+                })
+                .launch()
+                .await;
+        });
+}

+ 4 - 23
packages/liveview/src/lib.rs

@@ -2,29 +2,7 @@
 #![doc(html_logo_url = "https://avatars.githubusercontent.com/u/79236386")]
 #![doc(html_favicon_url = "https://avatars.githubusercontent.com/u/79236386")]
 
-pub mod adapters {
-    #[cfg(feature = "warp")]
-    pub mod warp_adapter;
-    #[cfg(feature = "warp")]
-    pub use warp_adapter::*;
-
-    #[cfg(feature = "axum")]
-    pub mod axum_adapter;
-    #[cfg(feature = "axum")]
-    pub use axum_adapter::*;
-
-    #[cfg(feature = "salvo")]
-    pub mod salvo_adapter;
-
-    #[cfg(feature = "salvo")]
-    pub use salvo_adapter::*;
-
-    #[cfg(feature = "rocket")]
-    pub mod rocket_adapter;
-    #[cfg(feature = "rocket")]
-    pub use rocket_adapter::*;
-}
-
+mod adapters;
 #[allow(unused_imports)]
 pub use adapters::*;
 
@@ -33,8 +11,11 @@ pub mod pool;
 mod query;
 use futures_util::{SinkExt, StreamExt};
 pub use pool::*;
+mod config;
 mod eval;
 mod events;
+pub use config::*;
+pub mod launch;
 
 pub trait WebsocketTx: SinkExt<String, Error = LiveViewError> {}
 impl<T> WebsocketTx for T where T: SinkExt<String, Error = LiveViewError> {}

+ 5 - 6
packages/router/src/history/liveview.rs

@@ -1,6 +1,6 @@
 use super::HistoryProvider;
 use crate::routable::Routable;
-use dioxus::prelude::*;
+use dioxus_lib::prelude::*;
 use serde::{Deserialize, Serialize};
 use std::sync::{Mutex, RwLock};
 use std::{collections::BTreeMap, rc::Rc, str::FromStr, sync::Arc};
@@ -172,8 +172,7 @@ where
         let updater_callback: Arc<RwLock<Arc<dyn Fn() + Send + Sync>>> =
             Arc::new(RwLock::new(Arc::new(|| {})));
 
-        let eval_provider =
-            consume_context::<Rc<dyn EvalProvider>>().expect("evaluator not provided");
+        let eval_provider = consume_context::<Rc<dyn EvalProvider>>();
 
         let create_eval = Rc::new(move |script: &str| {
             eval_provider
@@ -182,7 +181,7 @@ where
         }) as Rc<dyn Fn(&str) -> Result<UseEval, EvalError>>;
 
         // Listen to server actions
-        push_future({
+        spawn({
             let timeline = timeline.clone();
             let action_rx = action_rx.clone();
             let create_eval = create_eval.clone();
@@ -242,12 +241,12 @@ where
         });
 
         // Listen to browser actions
-        push_future({
+        spawn({
             let updater = updater_callback.clone();
             let timeline = timeline.clone();
             let create_eval = create_eval.clone();
             async move {
-                let popstate_eval = {
+                let mut popstate_eval = {
                     let init_eval = create_eval(
                         r#"
                         return [

+ 1 - 1
packages/router/src/router_cfg.rs

@@ -72,7 +72,7 @@ macro_rules! default_history {
             );
             // If we are not on wasm32 and the liveview feature is enabled, use the liveview history.
             #[cfg(all(feature = "liveview"))]
-            return Box::new(AnyHistoryProviderImplWrapper::new(LiveviewHistory::new($initial_route)));
+            return Box::new(AnyHistoryProviderImplWrapper::new(LiveviewHistory::new_with_initial_path($initial_route)));
             // Otherwise use the memory history.
             #[cfg(all(
                 not(all(target_arch = "wasm32", feature = "web")),