Browse Source

Merge pull request #1940 from DioxusLabs/jk/tweak-eval

calling `eval` should not return an error - eval() should always be available
Jonathan Kelley 1 năm trước cách đây
mục cha
commit
6cd9c695dc

+ 1 - 0
.vscode/settings.json

@@ -3,5 +3,6 @@
   "[toml]": {
     "editor.formatOnSave": false
   },
+  "rust-analyzer.check.workspace": true,
   "rust-analyzer.checkOnSave.allTargets": false,
 }

+ 1 - 2
examples/eval.rs

@@ -25,8 +25,7 @@ fn app() -> Element {
                 console.log(msg);
                 return "hi from JS!";
             "#,
-        )
-        .unwrap();
+        );
 
         // Send a message to the JS code.
         eval.send("Hi from Rust!".into()).unwrap();

+ 1 - 1
packages/desktop/headless_tests/events.rs

@@ -45,7 +45,7 @@ fn mock_event(id: &'static str, value: &'static str) {
                 value, id
             );
 
-            eval(&js).unwrap().await.unwrap();
+            eval(&js).await.unwrap();
         });
     })
 }

+ 0 - 1
packages/desktop/headless_tests/rendering.rs

@@ -38,7 +38,6 @@ fn use_inner_html(id: &'static str) -> Option<String> {
                     return element.innerHTML"#,
                 id
             ))
-            .unwrap()
             .await
             .unwrap();
 

+ 2 - 2
packages/desktop/src/eval.rs

@@ -15,8 +15,8 @@ impl DesktopEvalProvider {
 }
 
 impl EvalProvider for DesktopEvalProvider {
-    fn new_evaluator(&self, js: String) -> Result<GenerationalBox<Box<dyn Evaluator>>, EvalError> {
-        Ok(DesktopEvaluator::create(self.desktop_ctx.clone(), js))
+    fn new_evaluator(&self, js: String) -> GenerationalBox<Box<dyn Evaluator>> {
+        DesktopEvaluator::create(self.desktop_ctx.clone(), js)
     }
 }
 

+ 0 - 4
packages/fullstack/src/render.rs

@@ -44,10 +44,6 @@ impl SsrRendererPool {
                         .expect("couldn't spawn runtime")
                         .block_on(async move {
                             let mut vdom = virtual_dom_factory();
-                            vdom.in_runtime(|| {
-                                // Make sure the evaluator is initialized
-                                dioxus_ssr::eval::init_eval();
-                            });
                             let mut to = WriteBuffer { buffer: Vec::new() };
                             // before polling the future, we need to set the context
                             let prev_context =

+ 40 - 14
packages/html/src/eval.rs

@@ -1,7 +1,7 @@
 #![allow(clippy::await_holding_refcell_ref)]
 
 use dioxus_core::prelude::*;
-use generational_box::GenerationalBox;
+use generational_box::{AnyStorage, GenerationalBox, UnsyncStorage};
 use std::future::{poll_fn, Future, IntoFuture};
 use std::pin::Pin;
 use std::rc::Rc;
@@ -10,7 +10,7 @@ use std::task::{Context, Poll};
 /// A struct that implements EvalProvider is sent through [`ScopeState`]'s provide_context function
 /// so that [`use_eval`] can provide a platform agnostic interface for evaluating JavaScript code.
 pub trait EvalProvider {
-    fn new_evaluator(&self, js: String) -> Result<GenerationalBox<Box<dyn Evaluator>>, EvalError>;
+    fn new_evaluator(&self, js: String) -> GenerationalBox<Box<dyn Evaluator>>;
 }
 
 /// The platform's evaluator.
@@ -29,7 +29,7 @@ pub trait Evaluator {
     ) -> Poll<Result<serde_json::Value, EvalError>>;
 }
 
-type EvalCreator = Rc<dyn Fn(&str) -> Result<UseEval, EvalError>>;
+type EvalCreator = Rc<dyn Fn(&str) -> UseEval>;
 
 /// Get a struct that can execute any JavaScript.
 ///
@@ -43,19 +43,45 @@ type EvalCreator = Rc<dyn Fn(&str) -> Result<UseEval, EvalError>>;
 pub fn eval_provider() -> EvalCreator {
     let eval_provider = consume_context::<Rc<dyn EvalProvider>>();
 
-    Rc::new(move |script: &str| {
-        eval_provider
-            .new_evaluator(script.to_string())
-            .map(UseEval::new)
-    }) as Rc<dyn Fn(&str) -> Result<UseEval, EvalError>>
+    Rc::new(move |script: &str| UseEval::new(eval_provider.new_evaluator(script.to_string())))
+        as Rc<dyn Fn(&str) -> UseEval>
 }
 
-pub fn eval(script: &str) -> Result<UseEval, EvalError> {
-    let eval_provider = dioxus_core::prelude::consume_context::<Rc<dyn EvalProvider>>();
-
-    eval_provider
-        .new_evaluator(script.to_string())
-        .map(UseEval::new)
+pub fn eval(script: &str) -> UseEval {
+    let eval_provider = dioxus_core::prelude::try_consume_context::<Rc<dyn EvalProvider>>()
+        // Create a dummy provider that always hiccups when trying to evaluate
+        // That way, we can still compile and run the code without a real provider
+        .unwrap_or_else(|| {
+            struct DummyProvider;
+            impl EvalProvider for DummyProvider {
+                fn new_evaluator(&self, _js: String) -> GenerationalBox<Box<dyn Evaluator>> {
+                    UnsyncStorage::owner().insert(Box::new(DummyEvaluator))
+                }
+            }
+
+            struct DummyEvaluator;
+            impl Evaluator for DummyEvaluator {
+                fn send(&self, _data: serde_json::Value) -> Result<(), EvalError> {
+                    Err(EvalError::Unsupported)
+                }
+                fn poll_recv(
+                    &mut self,
+                    _context: &mut Context<'_>,
+                ) -> Poll<Result<serde_json::Value, EvalError>> {
+                    Poll::Ready(Err(EvalError::Unsupported))
+                }
+                fn poll_join(
+                    &mut self,
+                    _context: &mut Context<'_>,
+                ) -> Poll<Result<serde_json::Value, EvalError>> {
+                    Poll::Ready(Err(EvalError::Unsupported))
+                }
+            }
+
+            Rc::new(DummyProvider) as Rc<dyn EvalProvider>
+        });
+
+    UseEval::new(eval_provider.new_evaluator(script.to_string()))
 }
 
 /// A wrapper around the target platform's evaluator.

+ 2 - 2
packages/liveview/src/eval.rs

@@ -18,8 +18,8 @@ pub struct DesktopEvalProvider {
 }
 
 impl EvalProvider for DesktopEvalProvider {
-    fn new_evaluator(&self, js: String) -> Result<GenerationalBox<Box<dyn Evaluator>>, EvalError> {
-        Ok(DesktopEvaluator::create(self.query.clone(), js))
+    fn new_evaluator(&self, js: String) -> GenerationalBox<Box<dyn Evaluator>> {
+        DesktopEvaluator::create(self.query.clone(), js)
     }
 }
 

+ 5 - 6
packages/playwright-tests/web/src/main.rs

@@ -24,12 +24,11 @@ fn app() -> Element {
             class: "eval-button",
             onclick: move |_| async move {
                 let mut eval = eval(
-                        r#"
-                            window.document.title = 'Hello from Dioxus Eval!';
-                            dioxus.send("returned eval value");
-                        "#,
-                    )
-                    .unwrap();
+                    r#"
+                        window.document.title = 'Hello from Dioxus Eval!';
+                        dioxus.send("returned eval value");
+                    "#,
+                );
 
                 let result = eval.recv().await;
                 if let Ok(serde_json::Value::String(string)) = result {

+ 0 - 46
packages/ssr/src/eval.rs

@@ -1,46 +0,0 @@
-use async_trait::async_trait;
-use dioxus_core::ScopeId;
-use dioxus_html::prelude::{EvalError, EvalProvider, Evaluator};
-use generational_box::{AnyStorage, GenerationalBox, UnsyncStorage};
-use std::rc::Rc;
-
-/// Provides the SSREvalProvider through [`cx.provide_context`].
-pub fn init_eval() {
-    let provider: Rc<dyn EvalProvider> = Rc::new(SSREvalProvider {});
-    ScopeId::ROOT.provide_context(provider);
-}
-
-/// Reprents the ssr-target's provider of evaluators.
-pub struct SSREvalProvider;
-impl EvalProvider for SSREvalProvider {
-    fn new_evaluator(&self, _: String) -> Result<GenerationalBox<Box<dyn Evaluator>>, EvalError> {
-        let owner = UnsyncStorage::owner();
-        Ok(owner.insert(Box::new(SSREvaluator) as Box<dyn Evaluator + 'static>))
-    }
-}
-
-/// Represents a ssr-target's JavaScript evaluator.
-pub struct SSREvaluator;
-
-// In ssr rendering we never run or resolve evals.
-#[async_trait(?Send)]
-impl Evaluator for SSREvaluator {
-    /// Sends a message to the evaluated JavaScript.
-    fn send(&self, _el: serde_json::Value) -> Result<(), EvalError> {
-        Ok(())
-    }
-
-    fn poll_recv(
-        &mut self,
-        _cx: &mut std::task::Context<'_>,
-    ) -> std::task::Poll<Result<serde_json::Value, EvalError>> {
-        std::task::Poll::Pending
-    }
-
-    fn poll_join(
-        &mut self,
-        _cx: &mut std::task::Context<'_>,
-    ) -> std::task::Poll<Result<serde_json::Value, EvalError>> {
-        std::task::Poll::Pending
-    }
-}

+ 0 - 1
packages/ssr/src/incremental.rs

@@ -79,7 +79,6 @@ impl IncrementalRenderer {
     ) -> Result<RenderFreshness, IncrementalRendererError> {
         let mut html_buffer = WriteBuffer { buffer: Vec::new() };
         {
-            virtual_dom.in_runtime(crate::eval::init_eval);
             rebuild_with(&mut virtual_dom).await;
 
             renderer.render_before_body(&mut *html_buffer)?;

+ 0 - 2
packages/ssr/src/lib.rs

@@ -11,7 +11,6 @@ pub mod incremental;
 #[cfg(feature = "incremental")]
 mod incremental_cfg;
 
-pub mod eval;
 pub mod renderer;
 pub mod template;
 
@@ -29,7 +28,6 @@ pub fn render_element(element: Element) -> String {
     }
 
     let mut dom = VirtualDom::new_with_props(lazy_app, element);
-    dom.in_runtime(crate::eval::init_eval);
     dom.rebuild(&mut NoOpMutations);
 
     Renderer::new().render(&dom)

+ 13 - 15
packages/web/src/eval.rs

@@ -16,7 +16,7 @@ pub fn init_eval() {
 /// Represents the web-target's provider of evaluators.
 pub struct WebEvalProvider;
 impl EvalProvider for WebEvalProvider {
-    fn new_evaluator(&self, js: String) -> Result<GenerationalBox<Box<dyn Evaluator>>, EvalError> {
+    fn new_evaluator(&self, js: String) -> GenerationalBox<Box<dyn Evaluator>> {
         WebEvaluator::create(js)
     }
 }
@@ -33,12 +33,12 @@ const PROMISE_WRAPPER: &str = r#"
 struct WebEvaluator {
     dioxus: Dioxus,
     channel_receiver: futures_channel::mpsc::UnboundedReceiver<serde_json::Value>,
-    result: Option<serde_json::Value>,
+    result: Option<Result<serde_json::Value, EvalError>>,
 }
 
 impl WebEvaluator {
     /// Creates a new evaluator for web-based targets.
-    fn create(js: String) -> Result<GenerationalBox<Box<dyn Evaluator>>, EvalError> {
+    fn create(js: String) -> GenerationalBox<Box<dyn Evaluator>> {
         let (mut channel_sender, channel_receiver) = futures_channel::mpsc::unbounded();
         let owner = UnsyncStorage::owner();
         let invalid = owner.invalid();
@@ -69,23 +69,21 @@ impl WebEvaluator {
                         let string: String = stringified.into();
                         Value::from_str(&string).map_err(|e| {
                             EvalError::Communication(format!("Failed to parse result - {}", e))
-                        })?
+                        })
                     } else {
-                        return Err(EvalError::Communication(
+                        Err(EvalError::Communication(
                             "Failed to stringify result".into(),
-                        ));
+                        ))
                     }
                 } else {
-                    return Err(EvalError::Communication(
+                    Err(EvalError::Communication(
                         "Failed to stringify result".into(),
-                    ));
+                    ))
                 }
             }
-            Err(err) => {
-                return Err(EvalError::InvalidJs(
-                    err.as_string().unwrap_or("unknown".to_string()),
-                ));
-            }
+            Err(err) => Err(EvalError::InvalidJs(
+                err.as_string().unwrap_or("unknown".to_string()),
+            )),
         };
 
         invalid.set(Box::new(Self {
@@ -94,7 +92,7 @@ impl WebEvaluator {
             result: Some(result),
         }) as Box<dyn Evaluator + 'static>);
 
-        Ok(invalid)
+        invalid
     }
 }
 
@@ -105,7 +103,7 @@ impl Evaluator for WebEvaluator {
         _cx: &mut std::task::Context<'_>,
     ) -> std::task::Poll<Result<serde_json::Value, EvalError>> {
         if let Some(result) = self.result.take() {
-            std::task::Poll::Ready(Ok(result))
+            std::task::Poll::Ready(result)
         } else {
             std::task::Poll::Ready(Err(EvalError::Finished))
         }