- Don't merge dynamic attributes together unnecessarily - Walk the workspace until we find a target dir with the dioxusin handle
This commit is contained in:
11 files changed
+259
-31
No files matched your search
@@ -0,0 +1,32 @@
|
|||||||
|
use dioxus::dioxus_core::{ElementId, Mutation::*};
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
/// Make sure that rsx! is parsing templates and their attributes properly
|
||||||
|
#[test]
|
||||||
|
fn attributes_pass_properly() {
|
||||||
|
let h = rsx! {
|
||||||
|
circle {
|
||||||
|
cx: 50,
|
||||||
|
cy: 50,
|
||||||
|
r: 40,
|
||||||
|
stroke: "green",
|
||||||
|
fill: "yellow"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let o = h.unwrap();
|
||||||
|
|
||||||
|
let template = &o.template.get();
|
||||||
|
|
||||||
|
assert_eq!(template.attr_paths.len(), 3);
|
||||||
|
|
||||||
|
let _circle = template.roots[0];
|
||||||
|
let TemplateNode::Element { attrs, tag, namespace, children } = _circle else {
|
||||||
|
panic!("Expected an element");
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(tag, "circle");
|
||||||
|
assert_eq!(namespace, Some("http://www.w3.org/2000/svg"));
|
||||||
|
assert_eq!(children.len(), 0);
|
||||||
|
assert_eq!(attrs.len(), 5);
|
||||||
|
}
|
||||||
@@ -31,10 +31,35 @@ pub enum HotReloadMsg {
|
|||||||
/// Connect to the hot reloading listener. The callback provided will be called every time a template change is detected
|
/// Connect to the hot reloading listener. The callback provided will be called every time a template change is detected
|
||||||
pub fn connect(mut callback: impl FnMut(HotReloadMsg) + Send + 'static) {
|
pub fn connect(mut callback: impl FnMut(HotReloadMsg) + Send + 'static) {
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
let path = PathBuf::from("./").join("target").join("dioxusin");
|
// get the cargo manifest directory, where the target dir lives
|
||||||
|
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||||
|
|
||||||
|
// walk the path until we a find a socket named `dioxusin` inside that folder's target directory
|
||||||
|
loop {
|
||||||
|
let maybe = path.join("target").join("dioxusin");
|
||||||
|
|
||||||
|
if maybe.exists() {
|
||||||
|
path = maybe;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
path = match path.parent() {
|
||||||
|
Some(parent) => parent.to_path_buf(),
|
||||||
|
None => {
|
||||||
|
return eprintln!(
|
||||||
|
"could not find hot reloading server for crate at {}",
|
||||||
|
env!("CARGO_MANIFEST_DIR")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// There might be a socket since the we're not running under the hot reloading server
|
// There might be a socket since the we're not running under the hot reloading server
|
||||||
let Ok(socket) = LocalSocketStream::connect(path) else {
|
let Ok(socket) = LocalSocketStream::connect(path.clone()) else {
|
||||||
|
println!(
|
||||||
|
"could not find hot reloading server at {:?}, make sure it's running",
|
||||||
|
path
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+12
-12
@@ -9,16 +9,16 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@playwright/test": "^1.41.2"
|
"@playwright/test": "^1.42.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@playwright/test": {
|
"node_modules/@playwright/test": {
|
||||||
"version": "1.41.2",
|
"version": "1.42.1",
|
||||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.41.2.tgz",
|
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.42.1.tgz",
|
||||||
"integrity": "sha512-qQB9h7KbibJzrDpkXkYvsmiDJK14FULCCZgEcoe2AvFAS64oCirWTwzTlAYEbKaRxWs5TFesE1Na6izMv3HfGg==",
|
"integrity": "sha512-Gq9rmS54mjBL/7/MvBaNOBwbfnh7beHvS6oS4srqXFcQHpQCV1+c8JXWE8VLPyRDhgS3H8x8A7hztqI9VnwrAQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"playwright": "1.41.2"
|
"playwright": "1.42.1"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"playwright": "cli.js"
|
"playwright": "cli.js"
|
||||||
@@ -42,12 +42,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/playwright": {
|
"node_modules/playwright": {
|
||||||
"version": "1.41.2",
|
"version": "1.42.1",
|
||||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.41.2.tgz",
|
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.42.1.tgz",
|
||||||
"integrity": "sha512-v0bOa6H2GJChDL8pAeLa/LZC4feoAMbSQm1/jF/ySsWWoaNItvrMP7GEkvEEFyCTUYKMxjQKaTSg5up7nR6/8A==",
|
"integrity": "sha512-PgwB03s2DZBcNRoW+1w9E+VkLBxweib6KTXM0M3tkiT4jVxKSi6PmVJ591J+0u10LUrgxB7dLRbiJqO5s2QPMg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"playwright-core": "1.41.2"
|
"playwright-core": "1.42.1"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"playwright": "cli.js"
|
"playwright": "cli.js"
|
||||||
@@ -60,9 +60,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/playwright-core": {
|
"node_modules/playwright-core": {
|
||||||
"version": "1.41.2",
|
"version": "1.42.1",
|
||||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.41.2.tgz",
|
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.42.1.tgz",
|
||||||
"integrity": "sha512-VaTvwCA4Y8kxEe+kfm2+uUUw5Lubf38RxF7FpBxLPmGe5sdNkSg5e3ChEigaGrX7qdqT3pt2m/98LiyvU2x6CA==",
|
"integrity": "sha512-mxz6zclokgrke9p1vtdy/COWBH+eOZgYUVVU34C73M+4j4HLlQJHtfcqiqqxpP0o8HhMkflvfbquLX5dg6wlfA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"playwright-core": "cli.js"
|
"playwright-core": "cli.js"
|
||||||
|
|||||||
@@ -12,6 +12,6 @@
|
|||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@playwright/test": "^1.41.2"
|
"@playwright/test": "^1.42.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+6
-16
@@ -453,7 +453,8 @@ impl<'a> DynamicContext<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_static_node(&mut self, root: &'a BodyNode) -> TokenStream2 {
|
/// Render a portion of an rsx callbody to a token stream
|
||||||
|
pub fn render_static_node(&mut self, root: &'a BodyNode) -> TokenStream2 {
|
||||||
match root {
|
match root {
|
||||||
BodyNode::Element(el) => {
|
BodyNode::Element(el) => {
|
||||||
let el_name = &el.name;
|
let el_name = &el.name;
|
||||||
@@ -499,20 +500,10 @@ impl<'a> DynamicContext<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
// If this attribute is dynamic, but it already exists in the template, we can reuse the index
|
let ct = self.dynamic_attributes.len();
|
||||||
if let Some(attribute_index) = self
|
self.dynamic_attributes.push(vec![attr]);
|
||||||
.attr_paths
|
self.attr_paths.push(self.current_path.clone());
|
||||||
.iter()
|
quote! { dioxus_core::TemplateAttribute::Dynamic { id: #ct }, }
|
||||||
.position(|path| path == &self.current_path)
|
|
||||||
{
|
|
||||||
self.dynamic_attributes[attribute_index].push(attr);
|
|
||||||
quote! {}
|
|
||||||
} else {
|
|
||||||
let ct = self.dynamic_attributes.len();
|
|
||||||
self.dynamic_attributes.push(vec![attr]);
|
|
||||||
self.attr_paths.push(self.current_path.clone());
|
|
||||||
quote! { dioxus_core::TemplateAttribute::Dynamic { id: #ct }, }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -525,7 +516,6 @@ impl<'a> DynamicContext<'a> {
|
|||||||
out
|
out
|
||||||
});
|
});
|
||||||
|
|
||||||
let _opt = el.children.len() == 1;
|
|
||||||
let children = quote! { #(#children),* };
|
let children = quote! { #(#children),* };
|
||||||
|
|
||||||
let ns = ns(quote!(NAME_SPACE));
|
let ns = ns(quote!(NAME_SPACE));
|
||||||
|
|||||||
@@ -28,6 +28,16 @@ fn hotreloads() {
|
|||||||
diff_rsx(&new, &old),
|
diff_rsx(&new, &old),
|
||||||
DiffResult::RsxChanged { .. }
|
DiffResult::RsxChanged { .. }
|
||||||
));
|
));
|
||||||
|
|
||||||
|
let (old, new) = load_files(
|
||||||
|
include_str!("./valid/combo.old.rsx"),
|
||||||
|
include_str!("./valid/combo.new.rsx"),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(matches!(
|
||||||
|
diff_rsx(&new, &old),
|
||||||
|
DiffResult::RsxChanged { .. }
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
use dioxus_rsx::{CallBody, DynamicContext};
|
||||||
|
use syn::Item;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rsx_writeout_snapshot() {
|
||||||
|
let body = parse_from_str(include_str!("./parsing/multiexpr.rsx"));
|
||||||
|
|
||||||
|
assert_eq!(body.roots.len(), 1);
|
||||||
|
|
||||||
|
let root = &body.roots[0];
|
||||||
|
|
||||||
|
let el = match root {
|
||||||
|
dioxus_rsx::BodyNode::Element(el) => el,
|
||||||
|
_ => panic!("Expected an element"),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(el.name, "circle");
|
||||||
|
|
||||||
|
assert_eq!(el.attributes.len(), 5);
|
||||||
|
|
||||||
|
let mut context = DynamicContext::default();
|
||||||
|
let o = context.render_static_node(&body.roots[0]);
|
||||||
|
|
||||||
|
// hi!!!!!
|
||||||
|
// you're probably here because you changed something in how rsx! generates templates and need to update the snapshot
|
||||||
|
// This is a snapshot test. Make sure the contents are checked before committing a new snapshot.
|
||||||
|
let stability_tested = o.to_string();
|
||||||
|
assert_eq!(
|
||||||
|
stability_tested.trim(),
|
||||||
|
include_str!("./parsing/multiexpr.expanded.rsx").trim()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_from_str(contents: &str) -> CallBody {
|
||||||
|
// Parse the file
|
||||||
|
let file = syn::parse_file(contents).unwrap();
|
||||||
|
|
||||||
|
// The first token should be the macro call
|
||||||
|
let Item::Macro(call) = file.items.first().unwrap() else {
|
||||||
|
panic!("Expected a macro call");
|
||||||
|
};
|
||||||
|
|
||||||
|
call.mac.parse_body().unwrap()
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
dioxus_core :: TemplateNode :: Element { tag : dioxus_elements :: circle :: TAG_NAME , namespace : dioxus_elements :: circle :: NAME_SPACE , attrs : & [dioxus_core :: TemplateAttribute :: Dynamic { id : 0usize } , dioxus_core :: TemplateAttribute :: Dynamic { id : 1usize } , dioxus_core :: TemplateAttribute :: Dynamic { id : 2usize } , dioxus_core :: TemplateAttribute :: Static { name : dioxus_elements :: circle :: stroke . 0 , namespace : dioxus_elements :: circle :: stroke . 1 , value : "green" , } , dioxus_core :: TemplateAttribute :: Static { name : dioxus_elements :: circle :: fill . 0 , namespace : dioxus_elements :: circle :: fill . 1 , value : "yellow" , } ,] , children : & [] , }
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
rsx! {
|
||||||
|
circle {
|
||||||
|
cx: 50,
|
||||||
|
cy: 50,
|
||||||
|
r: 40,
|
||||||
|
stroke: "green",
|
||||||
|
fill: "yellow"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
// This test is used by playwright configured in the root of the repo
|
||||||
|
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
fn app() -> Element {
|
||||||
|
let mut num = use_signal(|| 0);
|
||||||
|
let mut eval_result = use_signal(String::new);
|
||||||
|
let a = 123;
|
||||||
|
|
||||||
|
rsx! {
|
||||||
|
div {
|
||||||
|
"hello axum! {num}"
|
||||||
|
button { class: "increment-button", onclick: move |_| num += 1, "Increment" }
|
||||||
|
}
|
||||||
|
svg { circle { cx: 50, cy: 50, r: 40, stroke: "green", fill: "yellow" } }
|
||||||
|
div { class: "raw-attribute-div", "raw-attribute": "raw-attribute-value" }
|
||||||
|
div { class: "hidden-attribute-div", hidden: true }
|
||||||
|
div {
|
||||||
|
class: "dangerous-inner-html-div",
|
||||||
|
dangerous_inner_html: "<p>hello dangerous inner html</p>"
|
||||||
|
}
|
||||||
|
input { value: "hello input" }
|
||||||
|
div { class: "style-div", color: "red", "colored text" }
|
||||||
|
div { class: "style-div", color: "red", "colored text" }
|
||||||
|
button {
|
||||||
|
class: "eval-button",
|
||||||
|
onclick: move |_| async move {
|
||||||
|
let mut eval = eval(
|
||||||
|
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 {
|
||||||
|
eval_result.set(string);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Eval!!!!"
|
||||||
|
"Eval!!!!"
|
||||||
|
"Eval!!!!!"
|
||||||
|
"Eval!!!!"
|
||||||
|
"Eval!!!!"
|
||||||
|
"Eval!!!!"
|
||||||
|
}
|
||||||
|
div { class: "eval-result", "{eval_result}" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// tracing_wasm::set_as_global_default_with_config(
|
||||||
|
// tracing_wasm::WASMLayerConfigBuilder::default()
|
||||||
|
// .set_max_level(tracing::Level::TRACE)
|
||||||
|
// .build(),
|
||||||
|
// );
|
||||||
|
launch(app);
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
// This test is used by playwright configured in the root of the repo
|
||||||
|
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
fn app() -> Element {
|
||||||
|
let mut num = use_signal(|| 0);
|
||||||
|
let mut eval_result = use_signal(String::new);
|
||||||
|
let a = 123;
|
||||||
|
|
||||||
|
rsx! {
|
||||||
|
div {
|
||||||
|
"hello axum! {num}"
|
||||||
|
button { class: "increment-button", onclick: move |_| num += 1, "Increment" }
|
||||||
|
}
|
||||||
|
svg { circle { cx: 50, cy: 50, r: 40, stroke: "green", fill: "yellow" } }
|
||||||
|
div { class: "raw-attribute-div", "raw-attribute": "raw-attribute-value" }
|
||||||
|
div { class: "hidden-attribute-div", hidden: true }
|
||||||
|
div {
|
||||||
|
class: "dangerous-inner-html-div",
|
||||||
|
dangerous_inner_html: "<p>hello dangerous inner html</p>"
|
||||||
|
}
|
||||||
|
input { value: "hello input" }
|
||||||
|
div { class: "style-div", color: "red", "colored text" }
|
||||||
|
div { class: "style-div", color: "red", "colored text" }
|
||||||
|
button {
|
||||||
|
class: "eval-button",
|
||||||
|
onclick: move |_| async move {
|
||||||
|
let mut eval = eval(
|
||||||
|
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 {
|
||||||
|
eval_result.set(string);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Eval!!!!"
|
||||||
|
"Eval!!!!"
|
||||||
|
"Eval!!!!!"
|
||||||
|
"Eval!!!!"
|
||||||
|
"Eval!!!!"
|
||||||
|
}
|
||||||
|
div { class: "eval-result", "{eval_result}" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// tracing_wasm::set_as_global_default_with_config(
|
||||||
|
// tracing_wasm::WASMLayerConfigBuilder::default()
|
||||||
|
// .set_max_level(tracing::Level::TRACE)
|
||||||
|
// .build(),
|
||||||
|
// );
|
||||||
|
launch(app);
|
||||||
|
}
|
||||||
Reference in new issue
Block a user