mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-14 00:17:17 +00:00
Improve compile times by splitting out rsx-hotreload from rsx (#2971)
* fix imports, migrate over rsx-hotreload
This commit is contained in:
parent
b67122dd2a
commit
463e67cd12
41 changed files with 188 additions and 190 deletions
21
Cargo.lock
generated
21
Cargo.lock
generated
|
@ -2510,9 +2510,11 @@ dependencies = [
|
||||||
"dioxus-check",
|
"dioxus-check",
|
||||||
"dioxus-cli-config",
|
"dioxus-cli-config",
|
||||||
"dioxus-core",
|
"dioxus-core",
|
||||||
|
"dioxus-core-types",
|
||||||
"dioxus-hot-reload",
|
"dioxus-hot-reload",
|
||||||
"dioxus-html",
|
"dioxus-html",
|
||||||
"dioxus-rsx",
|
"dioxus-rsx",
|
||||||
|
"dioxus-rsx-hotreload",
|
||||||
"dioxus-rsx-rosetta",
|
"dioxus-rsx-rosetta",
|
||||||
"dirs",
|
"dirs",
|
||||||
"env_logger 0.11.5",
|
"env_logger 0.11.5",
|
||||||
|
@ -2792,6 +2794,7 @@ dependencies = [
|
||||||
"dioxus-core",
|
"dioxus-core",
|
||||||
"dioxus-html",
|
"dioxus-html",
|
||||||
"dioxus-rsx",
|
"dioxus-rsx",
|
||||||
|
"dioxus-rsx-hotreload",
|
||||||
"dioxus-signals",
|
"dioxus-signals",
|
||||||
"execute",
|
"execute",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
|
@ -2815,6 +2818,7 @@ dependencies = [
|
||||||
"dioxus",
|
"dioxus",
|
||||||
"dioxus-core",
|
"dioxus-core",
|
||||||
"dioxus-core-macro",
|
"dioxus-core-macro",
|
||||||
|
"dioxus-core-types",
|
||||||
"dioxus-hooks",
|
"dioxus-hooks",
|
||||||
"dioxus-html-internal-macro",
|
"dioxus-html-internal-macro",
|
||||||
"dioxus-rsx",
|
"dioxus-rsx",
|
||||||
|
@ -3033,14 +3037,25 @@ dependencies = [
|
||||||
name = "dioxus-rsx"
|
name = "dioxus-rsx"
|
||||||
version = "0.6.0-alpha.2"
|
version = "0.6.0-alpha.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dioxus-core",
|
|
||||||
"internment",
|
|
||||||
"prettier-please",
|
"prettier-please",
|
||||||
"prettyplease",
|
"prettyplease",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"proc-macro2-diagnostics",
|
"proc-macro2-diagnostics",
|
||||||
"quote",
|
"quote",
|
||||||
"serde",
|
"syn 2.0.77",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dioxus-rsx-hotreload"
|
||||||
|
version = "0.6.0-alpha.2"
|
||||||
|
dependencies = [
|
||||||
|
"dioxus-core",
|
||||||
|
"dioxus-core-types",
|
||||||
|
"dioxus-rsx",
|
||||||
|
"internment",
|
||||||
|
"proc-macro2",
|
||||||
|
"proc-macro2-diagnostics",
|
||||||
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.77",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
|
@ -24,6 +24,7 @@ members = [
|
||||||
"packages/autofmt",
|
"packages/autofmt",
|
||||||
"packages/check",
|
"packages/check",
|
||||||
"packages/rsx",
|
"packages/rsx",
|
||||||
|
"packages/rsx-hotreload",
|
||||||
"packages/rsx-rosetta",
|
"packages/rsx-rosetta",
|
||||||
"packages/generational-box",
|
"packages/generational-box",
|
||||||
"packages/signals",
|
"packages/signals",
|
||||||
|
@ -87,6 +88,7 @@ dioxus-liveview = { path = "packages/liveview", version = "0.6.0-alpha.0" }
|
||||||
dioxus-autofmt = { path = "packages/autofmt", version = "0.6.0-alpha.0" }
|
dioxus-autofmt = { path = "packages/autofmt", version = "0.6.0-alpha.0" }
|
||||||
dioxus-check = { path = "packages/check", version = "0.6.0-alpha.0" }
|
dioxus-check = { path = "packages/check", version = "0.6.0-alpha.0" }
|
||||||
dioxus-rsx = { path = "packages/rsx", version = "0.6.0-alpha.0" }
|
dioxus-rsx = { path = "packages/rsx", version = "0.6.0-alpha.0" }
|
||||||
|
dioxus-rsx-hotreload = { path = "packages/rsx-hotreload", version = "0.6.0-alpha.0" }
|
||||||
dioxus-rsx-rosetta = { path = "packages/rsx-rosetta", version = "0.6.0-alpha.0" }
|
dioxus-rsx-rosetta = { path = "packages/rsx-rosetta", version = "0.6.0-alpha.0" }
|
||||||
dioxus-signals = { path = "packages/signals", version = "0.6.0-alpha.0" }
|
dioxus-signals = { path = "packages/signals", version = "0.6.0-alpha.0" }
|
||||||
dioxus-cli-config = { path = "packages/cli-config", version = "0.6.0-alpha.0", default-features = false}
|
dioxus-cli-config = { path = "packages/cli-config", version = "0.6.0-alpha.0", default-features = false}
|
||||||
|
|
|
@ -121,7 +121,7 @@ impl Files {
|
||||||
|
|
||||||
fn enter_dir(&mut self, dir_id: usize) {
|
fn enter_dir(&mut self, dir_id: usize) {
|
||||||
let path = &self.path_names[dir_id];
|
let path = &self.path_names[dir_id];
|
||||||
self.current_path = path.clone();
|
self.current_path.clone_from(path);
|
||||||
self.reload_path_list();
|
self.reload_path_list();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,9 +90,11 @@ brotli = "6.0.0"
|
||||||
dioxus-autofmt = { workspace = true }
|
dioxus-autofmt = { workspace = true }
|
||||||
dioxus-check = { workspace = true }
|
dioxus-check = { workspace = true }
|
||||||
dioxus-rsx-rosetta = { workspace = true }
|
dioxus-rsx-rosetta = { workspace = true }
|
||||||
dioxus-rsx = { workspace = true, features = ["serde"]}
|
dioxus-rsx = { workspace = true }
|
||||||
|
dioxus-rsx-hotreload = { workspace = true }
|
||||||
dioxus-html = { workspace = true, features = ["hot-reload-context"] }
|
dioxus-html = { workspace = true, features = ["hot-reload-context"] }
|
||||||
dioxus-core = { workspace = true, features = ["serialize"] }
|
dioxus-core = { workspace = true, features = ["serialize"] }
|
||||||
|
dioxus-core-types = { workspace = true }
|
||||||
dioxus-hot-reload = { workspace = true, features = ["serve"] }
|
dioxus-hot-reload = { workspace = true, features = ["serve"] }
|
||||||
ignore = "0.4.22"
|
ignore = "0.4.22"
|
||||||
env_logger = "0.11.3"
|
env_logger = "0.11.3"
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
use dioxus_core::internal::{HotReloadTemplateWithLocation, HotReloadedTemplate};
|
use dioxus_core::internal::{HotReloadTemplateWithLocation, HotReloadedTemplate};
|
||||||
use dioxus_rsx::{
|
use dioxus_core_types::HotReloadingContext;
|
||||||
hot_reload::{diff_rsx, ChangedRsx},
|
use dioxus_rsx::CallBody;
|
||||||
CallBody, HotReloadingContext,
|
use dioxus_rsx_hotreload::{diff_rsx, ChangedRsx};
|
||||||
};
|
|
||||||
use krates::cm::MetadataCommand;
|
use krates::cm::MetadataCommand;
|
||||||
use krates::Cmd;
|
use krates::Cmd;
|
||||||
pub use std::collections::HashMap;
|
pub use std::collections::HashMap;
|
||||||
|
@ -155,7 +154,7 @@ impl FileMap {
|
||||||
let template_location = template_location(old_start, file);
|
let template_location = template_location(old_start, file);
|
||||||
|
|
||||||
// Returns a list of templates that are hotreloadable
|
// Returns a list of templates that are hotreloadable
|
||||||
let hotreload_result = dioxus_rsx::hot_reload::HotReloadResult::new::<Ctx>(
|
let hotreload_result = dioxus_rsx_hotreload::HotReloadResult::new::<Ctx>(
|
||||||
&old_call_body.body,
|
&old_call_body.body,
|
||||||
&new_call_body.body,
|
&new_call_body.body,
|
||||||
template_location.clone(),
|
template_location.clone(),
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
pub mod bubbles;
|
pub mod bubbles;
|
||||||
|
pub mod hr_context;
|
||||||
|
|
||||||
pub use bubbles::*;
|
pub use bubbles::*;
|
||||||
|
pub use hr_context::*;
|
||||||
|
|
|
@ -10,7 +10,8 @@ description = "Hot reloading utilities for Dioxus"
|
||||||
keywords = ["dom", "ui", "gui", "react", "hot-reloading"]
|
keywords = ["dom", "ui", "gui", "react", "hot-reloading"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
dioxus-rsx = { workspace = true, features = ["serde"] }
|
dioxus-rsx = { workspace = true }
|
||||||
|
dioxus-rsx-hotreload = { workspace = true }
|
||||||
dioxus-core = { workspace = true, features = ["serialize"] }
|
dioxus-core = { workspace = true, features = ["serialize"] }
|
||||||
dioxus-html = { workspace = true, optional = true }
|
dioxus-html = { workspace = true, optional = true }
|
||||||
dioxus-signals = { workspace = true, optional = true }
|
dioxus-signals = { workspace = true, optional = true }
|
||||||
|
|
|
@ -12,6 +12,7 @@ keywords = ["dom", "ui", "gui", "react"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
dioxus-core = { workspace = true }
|
dioxus-core = { workspace = true }
|
||||||
dioxus-core-macro = { workspace = true }
|
dioxus-core-macro = { workspace = true }
|
||||||
|
dioxus-core-types = { workspace = true }
|
||||||
dioxus-rsx = { workspace = true, optional = true }
|
dioxus-rsx = { workspace = true, optional = true }
|
||||||
dioxus-html-internal-macro = { workspace = true }
|
dioxus-html-internal-macro = { workspace = true }
|
||||||
dioxus-hooks = { workspace = true }
|
dioxus-hooks = { workspace = true }
|
||||||
|
@ -96,7 +97,7 @@ file-engine = [
|
||||||
]
|
]
|
||||||
wasm-bind = ["dep:web-sys", "dep:wasm-bindgen", "dep:wasm-bindgen-futures"]
|
wasm-bind = ["dep:web-sys", "dep:wasm-bindgen", "dep:wasm-bindgen-futures"]
|
||||||
native-bind = ["dep:tokio", "file-engine"]
|
native-bind = ["dep:tokio", "file-engine"]
|
||||||
hot-reload-context = ["dep:dioxus-rsx", "dioxus-rsx/hot_reload_traits"]
|
hot-reload-context = ["dep:dioxus-rsx"]
|
||||||
html-to-rsx = []
|
html-to-rsx = []
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
|
|
||||||
use dioxus_core::prelude::IntoAttributeValue;
|
use dioxus_core::prelude::IntoAttributeValue;
|
||||||
use dioxus_core::HasAttributes;
|
use dioxus_core::HasAttributes;
|
||||||
use dioxus_html_internal_macro::impl_extension_attributes;
|
|
||||||
#[cfg(feature = "hot-reload-context")]
|
#[cfg(feature = "hot-reload-context")]
|
||||||
use dioxus_rsx::HotReloadingContext;
|
use dioxus_core_types::HotReloadingContext;
|
||||||
|
use dioxus_html_internal_macro::impl_extension_attributes;
|
||||||
|
|
||||||
#[cfg(feature = "hot-reload-context")]
|
#[cfg(feature = "hot-reload-context")]
|
||||||
use crate::{map_global_attributes, map_svg_attributes};
|
use crate::{map_global_attributes, map_svg_attributes};
|
||||||
|
|
15
packages/rsx-hotreload/Cargo.toml
Normal file
15
packages/rsx-hotreload/Cargo.toml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
[package]
|
||||||
|
name = "dioxus-rsx-hotreload"
|
||||||
|
edition = "2021"
|
||||||
|
version.workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
dioxus-rsx = { workspace = true }
|
||||||
|
internment = { workspace = true }
|
||||||
|
proc-macro2 = { workspace = true, features = ["span-locations"] }
|
||||||
|
proc-macro2-diagnostics = { workspace = true }
|
||||||
|
quote = { workspace = true }
|
||||||
|
syn = { workspace = true, features = ["full", "extra-traits", "visit", "visit-mut"] }
|
||||||
|
tracing = { workspace = true }
|
||||||
|
dioxus-core = { workspace = true }
|
||||||
|
dioxus-core-types = { workspace = true }
|
|
@ -63,14 +63,16 @@
|
||||||
//! The subproblem is optimal because the alternative is leaving less dynamic items for the remaining templates to hot reload which just makes it
|
//! The subproblem is optimal because the alternative is leaving less dynamic items for the remaining templates to hot reload which just makes it
|
||||||
//! more difficult to match future templates.
|
//! more difficult to match future templates.
|
||||||
|
|
||||||
use crate::innerlude::*;
|
|
||||||
use crate::HotReloadingContext;
|
|
||||||
use dioxus_core::internal::{
|
use dioxus_core::internal::{
|
||||||
FmtedSegments, HotReloadAttributeValue, HotReloadDynamicAttribute, HotReloadDynamicNode,
|
FmtedSegments, HotReloadAttributeValue, HotReloadDynamicAttribute, HotReloadDynamicNode,
|
||||||
HotReloadLiteral, HotReloadedTemplate, NamedAttribute,
|
HotReloadLiteral, HotReloadedTemplate, NamedAttribute,
|
||||||
};
|
};
|
||||||
|
use dioxus_core_types::HotReloadingContext;
|
||||||
|
use dioxus_rsx::*;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::extensions::{html_tag_and_namespace, intern, to_template_node};
|
||||||
|
|
||||||
use super::last_build_state::LastBuildState;
|
use super::last_build_state::LastBuildState;
|
||||||
|
|
||||||
/// A result of hot reloading
|
/// A result of hot reloading
|
||||||
|
@ -193,7 +195,7 @@ impl HotReloadResult {
|
||||||
let roots: Vec<_> = new
|
let roots: Vec<_> = new
|
||||||
.roots
|
.roots
|
||||||
.iter()
|
.iter()
|
||||||
.map(|node| node.to_template_node::<Ctx>())
|
.map(|node| to_template_node::<Ctx>(node))
|
||||||
.collect();
|
.collect();
|
||||||
let roots: &[dioxus_core::TemplateNode] = intern(&*roots);
|
let roots: &[dioxus_core::TemplateNode] = intern(&*roots);
|
||||||
|
|
||||||
|
@ -589,7 +591,7 @@ impl HotReloadResult {
|
||||||
&mut self,
|
&mut self,
|
||||||
attribute: &Attribute,
|
attribute: &Attribute,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
let (tag, namespace) = attribute.html_tag_and_namespace::<Ctx>();
|
let (tag, namespace) = html_tag_and_namespace::<Ctx>(attribute);
|
||||||
|
|
||||||
// If the attribute is a spread, try to grab it from the last build
|
// If the attribute is a spread, try to grab it from the last build
|
||||||
// If it wasn't in the last build with the same name, we can't hot reload it
|
// If it wasn't in the last build with the same name, we can't hot reload it
|
111
packages/rsx-hotreload/src/extensions.rs
Normal file
111
packages/rsx-hotreload/src/extensions.rs
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
use dioxus_core::TemplateNode;
|
||||||
|
use dioxus_core_types::HotReloadingContext;
|
||||||
|
use dioxus_rsx::*;
|
||||||
|
use internment::Intern;
|
||||||
|
use std::hash::Hash;
|
||||||
|
|
||||||
|
// interns a object into a static object, reusing the value if it already exists
|
||||||
|
pub(crate) fn intern<T: Eq + Hash + Send + Sync + ?Sized + 'static>(
|
||||||
|
s: impl Into<Intern<T>>,
|
||||||
|
) -> &'static T {
|
||||||
|
s.into().as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn html_tag_and_namespace<Ctx: HotReloadingContext>(
|
||||||
|
attr: &Attribute,
|
||||||
|
) -> (&'static str, Option<&'static str>) {
|
||||||
|
let attribute_name_rust = attr.name.to_string();
|
||||||
|
let element_name = attr.el_name.as_ref().unwrap();
|
||||||
|
let rust_name = match element_name {
|
||||||
|
ElementName::Ident(i) => i.to_string(),
|
||||||
|
// If this is a web component, just use the name of the elements instead of mapping the attribute
|
||||||
|
// through the hot reloading context
|
||||||
|
ElementName::Custom(_) => return (intern(attribute_name_rust.as_str()), None),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ctx::map_attribute(&rust_name, &attribute_name_rust)
|
||||||
|
.unwrap_or((intern(attribute_name_rust.as_str()), None))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_template_attribute<Ctx: HotReloadingContext>(
|
||||||
|
attr: &Attribute,
|
||||||
|
) -> dioxus_core::TemplateAttribute {
|
||||||
|
use dioxus_core::TemplateAttribute;
|
||||||
|
|
||||||
|
// If it's a dynamic node, just return it
|
||||||
|
// For dynamic attributes, we need to check the mapping to see if that mapping exists
|
||||||
|
// todo: one day we could generate new dynamic attributes on the fly if they're a literal,
|
||||||
|
// or something sufficiently serializable
|
||||||
|
// (ie `checked`` being a bool and bools being interpretable)
|
||||||
|
//
|
||||||
|
// For now, just give up if that attribute doesn't exist in the mapping
|
||||||
|
if !attr.is_static_str_literal() {
|
||||||
|
let id = attr.dyn_idx.get();
|
||||||
|
return TemplateAttribute::Dynamic { id };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise it's a static node and we can build it
|
||||||
|
let (_, value) = attr.as_static_str_literal().unwrap();
|
||||||
|
let (name, namespace) = html_tag_and_namespace::<Ctx>(attr);
|
||||||
|
|
||||||
|
TemplateAttribute::Static {
|
||||||
|
name,
|
||||||
|
namespace,
|
||||||
|
value: intern(value.to_static().unwrap().as_str()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert this BodyNode into a TemplateNode.
|
||||||
|
///
|
||||||
|
/// dioxus-core uses this to understand templates at compiletime
|
||||||
|
pub fn to_template_node<Ctx: HotReloadingContext>(node: &BodyNode) -> dioxus_core::TemplateNode {
|
||||||
|
use dioxus_core::TemplateNode;
|
||||||
|
match node {
|
||||||
|
BodyNode::Element(el) => {
|
||||||
|
let rust_name = el.name.to_string();
|
||||||
|
|
||||||
|
let (tag, namespace) =
|
||||||
|
Ctx::map_element(&rust_name).unwrap_or((intern(rust_name.as_str()), None));
|
||||||
|
|
||||||
|
TemplateNode::Element {
|
||||||
|
tag,
|
||||||
|
namespace,
|
||||||
|
children: intern(
|
||||||
|
el.children
|
||||||
|
.iter()
|
||||||
|
.map(|c| to_template_node::<Ctx>(c))
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
),
|
||||||
|
attrs: intern(
|
||||||
|
el.merged_attributes
|
||||||
|
.iter()
|
||||||
|
.map(|attr| to_template_attribute::<Ctx>(attr))
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BodyNode::Text(text) => text_to_template_node(text),
|
||||||
|
BodyNode::RawExpr(exp) => TemplateNode::Dynamic {
|
||||||
|
id: exp.dyn_idx.get(),
|
||||||
|
},
|
||||||
|
BodyNode::Component(comp) => TemplateNode::Dynamic {
|
||||||
|
id: comp.dyn_idx.get(),
|
||||||
|
},
|
||||||
|
BodyNode::ForLoop(floop) => TemplateNode::Dynamic {
|
||||||
|
id: floop.dyn_idx.get(),
|
||||||
|
},
|
||||||
|
BodyNode::IfChain(chain) => TemplateNode::Dynamic {
|
||||||
|
id: chain.dyn_idx.get(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn text_to_template_node(node: &TextNode) -> TemplateNode {
|
||||||
|
match node.input.to_static() {
|
||||||
|
Some(text) => TemplateNode::Text {
|
||||||
|
text: intern(text.as_str()),
|
||||||
|
},
|
||||||
|
None => TemplateNode::Dynamic {
|
||||||
|
id: node.dyn_idx.get(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::innerlude::*;
|
|
||||||
use dioxus_core::internal::{FmtSegment, FmtedSegments, HotReloadLiteral};
|
use dioxus_core::internal::{FmtSegment, FmtedSegments, HotReloadLiteral};
|
||||||
|
use dioxus_rsx::*;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
|
||||||
/// A pool of items we can grab from during hot reloading.
|
/// A pool of items we can grab from during hot reloading.
|
9
packages/rsx-hotreload/src/lib.rs
Normal file
9
packages/rsx-hotreload/src/lib.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
mod collect;
|
||||||
|
pub use collect::*;
|
||||||
|
|
||||||
|
mod diff;
|
||||||
|
pub use diff::*;
|
||||||
|
|
||||||
|
mod last_build_state;
|
||||||
|
|
||||||
|
mod extensions;
|
|
@ -10,10 +10,9 @@ use dioxus_core::{
|
||||||
prelude::{Template, TemplateNode},
|
prelude::{Template, TemplateNode},
|
||||||
TemplateAttribute, VNode,
|
TemplateAttribute, VNode,
|
||||||
};
|
};
|
||||||
use dioxus_rsx::{
|
use dioxus_core_types::HotReloadingContext;
|
||||||
hot_reload::{self, diff_rsx, ChangedRsx, HotReloadResult},
|
use dioxus_rsx::CallBody;
|
||||||
CallBody, HotReloadingContext,
|
use dioxus_rsx_hotreload::{self, diff_rsx, ChangedRsx, HotReloadResult};
|
||||||
};
|
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::{quote, ToTokens};
|
use quote::{quote, ToTokens};
|
||||||
use syn::{parse::Parse, spanned::Spanned, token::Token, File};
|
use syn::{parse::Parse, spanned::Spanned, token::Token, File};
|
|
@ -1,4 +1,4 @@
|
||||||
use dioxus_rsx::hot_reload::diff_rsx;
|
use dioxus_rsx_hotreload::diff_rsx;
|
||||||
use syn::File;
|
use syn::File;
|
||||||
|
|
||||||
macro_rules! assert_rsx_changed {
|
macro_rules! assert_rsx_changed {
|
|
@ -13,20 +13,13 @@ keywords = ["dom", "ui", "gui", "react"]
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
quote = { workspace = true }
|
|
||||||
proc-macro2 = { workspace = true, features = ["span-locations"] }
|
proc-macro2 = { workspace = true, features = ["span-locations"] }
|
||||||
dioxus-core = { workspace = true, optional = true }
|
proc-macro2-diagnostics = { workspace = true }
|
||||||
|
quote = { workspace = true }
|
||||||
syn = { workspace = true, features = ["full", "extra-traits", "visit", "visit-mut"] }
|
syn = { workspace = true, features = ["full", "extra-traits", "visit", "visit-mut"] }
|
||||||
serde = { workspace = true, features = ["derive"], optional = true }
|
|
||||||
internment = { version = "0.7.0", optional = true }
|
|
||||||
tracing = { workspace = true }
|
|
||||||
proc-macro2-diagnostics = { version = "0.10", default-features = false }
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["hot_reload"]
|
default = []
|
||||||
hot_reload_traits = []
|
|
||||||
hot_reload = ["dep:internment", "dep:dioxus-core", "hot_reload_traits", "serde"]
|
|
||||||
serde = ["dep:serde", "dioxus-core/serialize"]
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
prettyplease = { workspace = true }
|
prettyplease = { workspace = true }
|
||||||
|
|
|
@ -166,52 +166,6 @@ impl Attribute {
|
||||||
self.as_static_str_literal().is_some()
|
self.as_static_str_literal().is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "hot_reload")]
|
|
||||||
pub(crate) fn html_tag_and_namespace<Ctx: crate::HotReloadingContext>(
|
|
||||||
&self,
|
|
||||||
) -> (&'static str, Option<&'static str>) {
|
|
||||||
let attribute_name_rust = self.name.to_string();
|
|
||||||
let element_name = self.el_name.as_ref().unwrap();
|
|
||||||
let rust_name = match element_name {
|
|
||||||
ElementName::Ident(i) => i.to_string(),
|
|
||||||
// If this is a web component, just use the name of the elements instead of mapping the attribute
|
|
||||||
// through the hot reloading context
|
|
||||||
ElementName::Custom(_) => return (intern(attribute_name_rust.as_str()), None),
|
|
||||||
};
|
|
||||||
|
|
||||||
Ctx::map_attribute(&rust_name, &attribute_name_rust)
|
|
||||||
.unwrap_or((intern(attribute_name_rust.as_str()), None))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "hot_reload")]
|
|
||||||
pub fn to_template_attribute<Ctx: crate::HotReloadingContext>(
|
|
||||||
&self,
|
|
||||||
) -> dioxus_core::TemplateAttribute {
|
|
||||||
use dioxus_core::TemplateAttribute;
|
|
||||||
|
|
||||||
// If it's a dynamic node, just return it
|
|
||||||
// For dynamic attributes, we need to check the mapping to see if that mapping exists
|
|
||||||
// todo: one day we could generate new dynamic attributes on the fly if they're a literal,
|
|
||||||
// or something sufficiently serializable
|
|
||||||
// (ie `checked`` being a bool and bools being interpretable)
|
|
||||||
//
|
|
||||||
// For now, just give up if that attribute doesn't exist in the mapping
|
|
||||||
if !self.is_static_str_literal() {
|
|
||||||
let id = self.dyn_idx.get();
|
|
||||||
return TemplateAttribute::Dynamic { id };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise it's a static node and we can build it
|
|
||||||
let (_, value) = self.as_static_str_literal().unwrap();
|
|
||||||
let (name, namespace) = self.html_tag_and_namespace::<Ctx>();
|
|
||||||
|
|
||||||
TemplateAttribute::Static {
|
|
||||||
name,
|
|
||||||
namespace,
|
|
||||||
value: intern(value.to_static().unwrap().as_str()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rendered_as_dynamic_attr(&self) -> TokenStream2 {
|
pub fn rendered_as_dynamic_attr(&self) -> TokenStream2 {
|
||||||
// Shortcut out with spreads
|
// Shortcut out with spreads
|
||||||
if let AttributeName::Spread(_) = self.name {
|
if let AttributeName::Spread(_) = self.name {
|
||||||
|
|
|
@ -253,7 +253,7 @@ impl Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterate over the props of the component (without spreads, key, and custom attributes)
|
// Iterate over the props of the component (without spreads, key, and custom attributes)
|
||||||
pub(crate) fn component_props(&self) -> impl Iterator<Item = &Attribute> {
|
pub fn component_props(&self) -> impl Iterator<Item = &Attribute> {
|
||||||
self.fields
|
self.fields
|
||||||
.iter()
|
.iter()
|
||||||
.filter(move |attr| !attr.name.is_likely_key())
|
.filter(move |attr| !attr.name.is_likely_key())
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
#[cfg(feature = "hot_reload")]
|
|
||||||
mod collect;
|
|
||||||
#[cfg(feature = "hot_reload")]
|
|
||||||
pub use collect::*;
|
|
||||||
|
|
||||||
#[cfg(feature = "hot_reload_traits")]
|
|
||||||
mod context;
|
|
||||||
#[cfg(feature = "hot_reload_traits")]
|
|
||||||
pub use context::*;
|
|
||||||
|
|
||||||
#[cfg(feature = "hot_reload")]
|
|
||||||
mod diff;
|
|
||||||
#[cfg(feature = "hot_reload")]
|
|
||||||
pub use diff::*;
|
|
||||||
|
|
||||||
#[cfg(feature = "hot_reload")]
|
|
||||||
mod last_build_state;
|
|
|
@ -78,11 +78,6 @@ pub use partial_closure::PartialClosure;
|
||||||
pub use rsx_call::*;
|
pub use rsx_call::*;
|
||||||
pub use template_body::TemplateBody;
|
pub use template_body::TemplateBody;
|
||||||
|
|
||||||
pub mod hot_reload;
|
|
||||||
|
|
||||||
#[cfg(feature = "hot_reload_traits")]
|
|
||||||
pub use hot_reload::HotReloadingContext;
|
|
||||||
|
|
||||||
use quote::{quote, ToTokens, TokenStreamExt};
|
use quote::{quote, ToTokens, TokenStreamExt};
|
||||||
use syn::{
|
use syn::{
|
||||||
parse::{Parse, ParseStream},
|
parse::{Parse, ParseStream},
|
||||||
|
|
|
@ -126,52 +126,6 @@ impl ToTokens for BodyNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BodyNode {
|
impl BodyNode {
|
||||||
/// Convert this BodyNode into a TemplateNode.
|
|
||||||
///
|
|
||||||
/// dioxus-core uses this to understand templates at compiletime
|
|
||||||
#[cfg(feature = "hot_reload")]
|
|
||||||
pub fn to_template_node<Ctx: crate::HotReloadingContext>(&self) -> dioxus_core::TemplateNode {
|
|
||||||
use dioxus_core::TemplateNode;
|
|
||||||
match self {
|
|
||||||
BodyNode::Element(el) => {
|
|
||||||
let rust_name = el.name.to_string();
|
|
||||||
|
|
||||||
let (tag, namespace) =
|
|
||||||
Ctx::map_element(&rust_name).unwrap_or((intern(rust_name.as_str()), None));
|
|
||||||
|
|
||||||
TemplateNode::Element {
|
|
||||||
tag,
|
|
||||||
namespace,
|
|
||||||
children: intern(
|
|
||||||
el.children
|
|
||||||
.iter()
|
|
||||||
.map(|c| c.to_template_node::<Ctx>())
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
),
|
|
||||||
attrs: intern(
|
|
||||||
el.merged_attributes
|
|
||||||
.iter()
|
|
||||||
.map(|attr| attr.to_template_attribute::<Ctx>())
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BodyNode::Text(text) => text.to_template_node(),
|
|
||||||
BodyNode::RawExpr(exp) => TemplateNode::Dynamic {
|
|
||||||
id: exp.dyn_idx.get(),
|
|
||||||
},
|
|
||||||
BodyNode::Component(comp) => TemplateNode::Dynamic {
|
|
||||||
id: comp.dyn_idx.get(),
|
|
||||||
},
|
|
||||||
BodyNode::ForLoop(floop) => TemplateNode::Dynamic {
|
|
||||||
id: floop.dyn_idx.get(),
|
|
||||||
},
|
|
||||||
BodyNode::IfChain(chain) => TemplateNode::Dynamic {
|
|
||||||
id: chain.dyn_idx.get(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_dyn_idx(&self) -> usize {
|
pub fn get_dyn_idx(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
BodyNode::Text(text) => text.dyn_idx.get(),
|
BodyNode::Text(text) => text.dyn_idx.get(),
|
||||||
|
|
|
@ -238,7 +238,7 @@ impl TemplateBody {
|
||||||
self.roots.is_empty()
|
self.roots.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn implicit_key(&self) -> Option<&AttributeValue> {
|
pub fn implicit_key(&self) -> Option<&AttributeValue> {
|
||||||
match self.roots.first() {
|
match self.roots.first() {
|
||||||
Some(BodyNode::Element(el)) => el.key(),
|
Some(BodyNode::Element(el)) => el.key(),
|
||||||
Some(BodyNode::Component(comp)) => comp.get_key(),
|
Some(BodyNode::Component(comp)) => comp.get_key(),
|
||||||
|
@ -310,7 +310,7 @@ impl TemplateBody {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate through the literal component properties of this rsx call in depth-first order
|
/// Iterate through the literal component properties of this rsx call in depth-first order
|
||||||
pub(crate) fn literal_component_properties(&self) -> impl Iterator<Item = &HotLiteral> + '_ {
|
pub fn literal_component_properties(&self) -> impl Iterator<Item = &HotLiteral> + '_ {
|
||||||
self.dynamic_nodes()
|
self.dynamic_nodes()
|
||||||
.filter_map(|node| {
|
.filter_map(|node| {
|
||||||
if let BodyNode::Component(component) = node {
|
if let BodyNode::Component(component) = node {
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
#[cfg(feature = "hot_reload")]
|
|
||||||
use dioxus_core::TemplateNode;
|
|
||||||
|
|
||||||
use crate::{literal::HotLiteral, location::DynIdx, HotReloadFormattedSegment, IfmtInput};
|
use crate::{literal::HotLiteral, location::DynIdx, HotReloadFormattedSegment, IfmtInput};
|
||||||
use proc_macro2::{Span, TokenStream as TokenStream2};
|
use proc_macro2::{Span, TokenStream as TokenStream2};
|
||||||
use quote::ToTokens;
|
use quote::ToTokens;
|
||||||
|
@ -62,19 +59,6 @@ impl TextNode {
|
||||||
pub fn is_static(&self) -> bool {
|
pub fn is_static(&self) -> bool {
|
||||||
self.input.is_static()
|
self.input.is_static()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "hot_reload")]
|
|
||||||
pub fn to_template_node(&self) -> TemplateNode {
|
|
||||||
use crate::intern;
|
|
||||||
match self.input.to_static() {
|
|
||||||
Some(text) => TemplateNode::Text {
|
|
||||||
text: intern(text.as_str()),
|
|
||||||
},
|
|
||||||
None => TemplateNode::Dynamic {
|
|
||||||
id: self.dyn_idx.get(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
|
|
||||||
#[cfg(feature = "hot_reload")]
|
|
||||||
use internment::Intern;
|
|
||||||
|
|
||||||
use proc_macro2::TokenStream as TokenStream2;
|
use proc_macro2::TokenStream as TokenStream2;
|
||||||
use std::{fmt::Debug, hash::Hash};
|
use std::{fmt::Debug, hash::Hash};
|
||||||
use syn::{
|
use syn::{
|
||||||
|
@ -11,14 +8,6 @@ use syn::{
|
||||||
Ident,
|
Ident,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// interns a object into a static object, reusing the value if it already exists
|
|
||||||
#[cfg(feature = "hot_reload")]
|
|
||||||
pub(crate) fn intern<T: Eq + Hash + Send + Sync + ?Sized + 'static>(
|
|
||||||
s: impl Into<Intern<T>>,
|
|
||||||
) -> &'static T {
|
|
||||||
s.into().as_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse a raw ident and return a new ident with the r# prefix added
|
/// Parse a raw ident and return a new ident with the r# prefix added
|
||||||
pub fn parse_raw_ident(parse_buffer: &ParseBuffer) -> syn::Result<Ident> {
|
pub fn parse_raw_ident(parse_buffer: &ParseBuffer) -> syn::Result<Ident> {
|
||||||
// First try to parse as a normal ident
|
// First try to parse as a normal ident
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
dioxus_core :: TemplateNode :: Element { tag : dioxus_elements :: elements :: circle :: TAG_NAME , namespace : dioxus_elements :: 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 :: elements :: circle :: stroke . 0 , namespace : dioxus_elements :: elements :: circle :: stroke . 1 , value : "green" , } , dioxus_core :: TemplateAttribute :: Static { name : dioxus_elements :: elements :: circle :: fill . 0 , namespace : dioxus_elements :: elements :: circle :: fill . 1 , value : "yellow" , } ,] , children : & [] , }
|
|
|
@ -1,11 +0,0 @@
|
||||||
|
|
||||||
rsx! {
|
|
||||||
circle {
|
|
||||||
cx: 50,
|
|
||||||
cy: 50,
|
|
||||||
r: 40,
|
|
||||||
stroke: "green",
|
|
||||||
fill: "yellow"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue