Merge pull request #1940 from DioxusLabs/jk/tweak-eval
calling `eval` should not return an error - eval() should always be available
This commit is contained in:
13 files changed
+64
-95
No files matched your search
Vendored
+1
@@ -3,5 +3,6 @@
|
|||||||
"[toml]": {
|
"[toml]": {
|
||||||
"editor.formatOnSave": false
|
"editor.formatOnSave": false
|
||||||
},
|
},
|
||||||
|
"rust-analyzer.check.workspace": true,
|
||||||
"rust-analyzer.checkOnSave.allTargets": false,
|
"rust-analyzer.checkOnSave.allTargets": false,
|
||||||
}
|
}
|
||||||
+1
-2
@@ -25,8 +25,7 @@ fn app() -> Element {
|
|||||||
console.log(msg);
|
console.log(msg);
|
||||||
return "hi from JS!";
|
return "hi from JS!";
|
||||||
"#,
|
"#,
|
||||||
)
|
);
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Send a message to the JS code.
|
// Send a message to the JS code.
|
||||||
eval.send("Hi from Rust!".into()).unwrap();
|
eval.send("Hi from Rust!".into()).unwrap();
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ fn mock_event(id: &'static str, value: &'static str) {
|
|||||||
value, id
|
value, id
|
||||||
);
|
);
|
||||||
|
|
||||||
eval(&js).unwrap().await.unwrap();
|
eval(&js).await.unwrap();
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ fn use_inner_html(id: &'static str) -> Option<String> {
|
|||||||
return element.innerHTML"#,
|
return element.innerHTML"#,
|
||||||
id
|
id
|
||||||
))
|
))
|
||||||
.unwrap()
|
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ impl DesktopEvalProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl EvalProvider for DesktopEvalProvider {
|
impl EvalProvider for DesktopEvalProvider {
|
||||||
fn new_evaluator(&self, js: String) -> Result<GenerationalBox<Box<dyn Evaluator>>, EvalError> {
|
fn new_evaluator(&self, js: String) -> GenerationalBox<Box<dyn Evaluator>> {
|
||||||
Ok(DesktopEvaluator::create(self.desktop_ctx.clone(), js))
|
DesktopEvaluator::create(self.desktop_ctx.clone(), js)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,10 +44,6 @@ impl SsrRendererPool {
|
|||||||
.expect("couldn't spawn runtime")
|
.expect("couldn't spawn runtime")
|
||||||
.block_on(async move {
|
.block_on(async move {
|
||||||
let mut vdom = virtual_dom_factory();
|
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() };
|
let mut to = WriteBuffer { buffer: Vec::new() };
|
||||||
// before polling the future, we need to set the context
|
// before polling the future, we need to set the context
|
||||||
let prev_context =
|
let prev_context =
|
||||||
|
|||||||
+39
-13
@@ -1,7 +1,7 @@
|
|||||||
#![allow(clippy::await_holding_refcell_ref)]
|
#![allow(clippy::await_holding_refcell_ref)]
|
||||||
|
|
||||||
use dioxus_core::prelude::*;
|
use dioxus_core::prelude::*;
|
||||||
use generational_box::GenerationalBox;
|
use generational_box::{AnyStorage, GenerationalBox, UnsyncStorage};
|
||||||
use std::future::{poll_fn, Future, IntoFuture};
|
use std::future::{poll_fn, Future, IntoFuture};
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::rc::Rc;
|
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
|
/// 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.
|
/// so that [`use_eval`] can provide a platform agnostic interface for evaluating JavaScript code.
|
||||||
pub trait EvalProvider {
|
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.
|
/// The platform's evaluator.
|
||||||
@@ -29,7 +29,7 @@ pub trait Evaluator {
|
|||||||
) -> Poll<Result<serde_json::Value, EvalError>>;
|
) -> 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.
|
/// 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 {
|
pub fn eval_provider() -> EvalCreator {
|
||||||
let eval_provider = consume_context::<Rc<dyn EvalProvider>>();
|
let eval_provider = consume_context::<Rc<dyn EvalProvider>>();
|
||||||
|
|
||||||
Rc::new(move |script: &str| {
|
Rc::new(move |script: &str| UseEval::new(eval_provider.new_evaluator(script.to_string())))
|
||||||
eval_provider
|
as Rc<dyn Fn(&str) -> UseEval>
|
||||||
.new_evaluator(script.to_string())
|
|
||||||
.map(UseEval::new)
|
|
||||||
}) as Rc<dyn Fn(&str) -> Result<UseEval, EvalError>>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eval(script: &str) -> Result<UseEval, EvalError> {
|
pub fn eval(script: &str) -> UseEval {
|
||||||
let eval_provider = dioxus_core::prelude::consume_context::<Rc<dyn EvalProvider>>();
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
eval_provider
|
struct DummyEvaluator;
|
||||||
.new_evaluator(script.to_string())
|
impl Evaluator for DummyEvaluator {
|
||||||
.map(UseEval::new)
|
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.
|
/// A wrapper around the target platform's evaluator.
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ pub struct DesktopEvalProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl EvalProvider for DesktopEvalProvider {
|
impl EvalProvider for DesktopEvalProvider {
|
||||||
fn new_evaluator(&self, js: String) -> Result<GenerationalBox<Box<dyn Evaluator>>, EvalError> {
|
fn new_evaluator(&self, js: String) -> GenerationalBox<Box<dyn Evaluator>> {
|
||||||
Ok(DesktopEvaluator::create(self.query.clone(), js))
|
DesktopEvaluator::create(self.query.clone(), js)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,12 +24,11 @@ fn app() -> Element {
|
|||||||
class: "eval-button",
|
class: "eval-button",
|
||||||
onclick: move |_| async move {
|
onclick: move |_| async move {
|
||||||
let mut eval = eval(
|
let mut eval = eval(
|
||||||
r#"
|
r#"
|
||||||
window.document.title = 'Hello from Dioxus Eval!';
|
window.document.title = 'Hello from Dioxus Eval!';
|
||||||
dioxus.send("returned eval value");
|
dioxus.send("returned eval value");
|
||||||
"#,
|
"#,
|
||||||
)
|
);
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let result = eval.recv().await;
|
let result = eval.recv().await;
|
||||||
if let Ok(serde_json::Value::String(string)) = result {
|
if let Ok(serde_json::Value::String(string)) = result {
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -79,7 +79,6 @@ impl IncrementalRenderer {
|
|||||||
) -> Result<RenderFreshness, IncrementalRendererError> {
|
) -> Result<RenderFreshness, IncrementalRendererError> {
|
||||||
let mut html_buffer = WriteBuffer { buffer: Vec::new() };
|
let mut html_buffer = WriteBuffer { buffer: Vec::new() };
|
||||||
{
|
{
|
||||||
virtual_dom.in_runtime(crate::eval::init_eval);
|
|
||||||
rebuild_with(&mut virtual_dom).await;
|
rebuild_with(&mut virtual_dom).await;
|
||||||
|
|
||||||
renderer.render_before_body(&mut *html_buffer)?;
|
renderer.render_before_body(&mut *html_buffer)?;
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ pub mod incremental;
|
|||||||
#[cfg(feature = "incremental")]
|
#[cfg(feature = "incremental")]
|
||||||
mod incremental_cfg;
|
mod incremental_cfg;
|
||||||
|
|
||||||
pub mod eval;
|
|
||||||
pub mod renderer;
|
pub mod renderer;
|
||||||
pub mod template;
|
pub mod template;
|
||||||
|
|
||||||
@@ -29,7 +28,6 @@ pub fn render_element(element: Element) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut dom = VirtualDom::new_with_props(lazy_app, element);
|
let mut dom = VirtualDom::new_with_props(lazy_app, element);
|
||||||
dom.in_runtime(crate::eval::init_eval);
|
|
||||||
dom.rebuild(&mut NoOpMutations);
|
dom.rebuild(&mut NoOpMutations);
|
||||||
|
|
||||||
Renderer::new().render(&dom)
|
Renderer::new().render(&dom)
|
||||||
|
|||||||
+13
-15
@@ -16,7 +16,7 @@ pub fn init_eval() {
|
|||||||
/// Represents the web-target's provider of evaluators.
|
/// Represents the web-target's provider of evaluators.
|
||||||
pub struct WebEvalProvider;
|
pub struct WebEvalProvider;
|
||||||
impl EvalProvider for 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)
|
WebEvaluator::create(js)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -33,12 +33,12 @@ const PROMISE_WRAPPER: &str = r#"
|
|||||||
struct WebEvaluator {
|
struct WebEvaluator {
|
||||||
dioxus: Dioxus,
|
dioxus: Dioxus,
|
||||||
channel_receiver: futures_channel::mpsc::UnboundedReceiver<serde_json::Value>,
|
channel_receiver: futures_channel::mpsc::UnboundedReceiver<serde_json::Value>,
|
||||||
result: Option<serde_json::Value>,
|
result: Option<Result<serde_json::Value, EvalError>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WebEvaluator {
|
impl WebEvaluator {
|
||||||
/// Creates a new evaluator for web-based targets.
|
/// 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 (mut channel_sender, channel_receiver) = futures_channel::mpsc::unbounded();
|
||||||
let owner = UnsyncStorage::owner();
|
let owner = UnsyncStorage::owner();
|
||||||
let invalid = owner.invalid();
|
let invalid = owner.invalid();
|
||||||
@@ -69,23 +69,21 @@ impl WebEvaluator {
|
|||||||
let string: String = stringified.into();
|
let string: String = stringified.into();
|
||||||
Value::from_str(&string).map_err(|e| {
|
Value::from_str(&string).map_err(|e| {
|
||||||
EvalError::Communication(format!("Failed to parse result - {}", e))
|
EvalError::Communication(format!("Failed to parse result - {}", e))
|
||||||
})?
|
})
|
||||||
} else {
|
} else {
|
||||||
return Err(EvalError::Communication(
|
Err(EvalError::Communication(
|
||||||
"Failed to stringify result".into(),
|
"Failed to stringify result".into(),
|
||||||
));
|
))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(EvalError::Communication(
|
Err(EvalError::Communication(
|
||||||
"Failed to stringify result".into(),
|
"Failed to stringify result".into(),
|
||||||
));
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => Err(EvalError::InvalidJs(
|
||||||
return Err(EvalError::InvalidJs(
|
err.as_string().unwrap_or("unknown".to_string()),
|
||||||
err.as_string().unwrap_or("unknown".to_string()),
|
)),
|
||||||
));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
invalid.set(Box::new(Self {
|
invalid.set(Box::new(Self {
|
||||||
@@ -94,7 +92,7 @@ impl WebEvaluator {
|
|||||||
result: Some(result),
|
result: Some(result),
|
||||||
}) as Box<dyn Evaluator + 'static>);
|
}) as Box<dyn Evaluator + 'static>);
|
||||||
|
|
||||||
Ok(invalid)
|
invalid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +103,7 @@ impl Evaluator for WebEvaluator {
|
|||||||
_cx: &mut std::task::Context<'_>,
|
_cx: &mut std::task::Context<'_>,
|
||||||
) -> std::task::Poll<Result<serde_json::Value, EvalError>> {
|
) -> std::task::Poll<Result<serde_json::Value, EvalError>> {
|
||||||
if let Some(result) = self.result.take() {
|
if let Some(result) = self.result.take() {
|
||||||
std::task::Poll::Ready(Ok(result))
|
std::task::Poll::Ready(result)
|
||||||
} else {
|
} else {
|
||||||
std::task::Poll::Ready(Err(EvalError::Finished))
|
std::task::Poll::Ready(Err(EvalError::Finished))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user