Jonathan Kelley 4 лет назад
Родитель
Сommit
56e7eb8

+ 2 - 1
Cargo.toml

@@ -14,6 +14,7 @@ dioxus-html = { path = "./packages/html", optional = true }
 dioxus-web = { path = "./packages/web", optional = true }
 dioxus-webview = { path = "./packages/webview", optional = true }
 dioxus-hooks = { path = "./packages/hooks", optional = true }
+dioxus-ssr = { path = "./packages/ssr", optional = true }
 
 
 [features]
@@ -30,7 +31,7 @@ default = [
 ]
 atoms = []
 macro = ["dioxus-core-macro"]
-ssr = []
+ssr = ["dioxus-ssr"]
 hooks = ["dioxus-hooks"]
 router = []
 html = ["dioxus-html"]

+ 27 - 27
README.md

@@ -12,7 +12,7 @@ fn App(cx: Context<()>) -> VNode {
     let mut count = use_state(cx, || 0);
 
     cx.render(rsx! {
-        h1 { "Hi-Five counter: {count}" }
+        h1 { "High-Five counter: {count}" }
         button { onclick: move |_| count += 1, "Up high!" }
         button { onclick: move |_| count -= 1, "Down low!" }
     })
@@ -96,32 +96,32 @@ Dioxus is heavily inspired by React, but we want your transition to feel like an
 
 ### Phase 1: The Basics
 
-| Feature                 | Dioxus | React | Notes for Dioxus                                      |
-| ----------------------- | ------ | ----- | ----------------------------------------------------- |
-| Conditional Rendering   | ✅      | ✅     | if/then to hide/show component                        |
-| Map, Iterator           | ✅      | ✅     | map/filter/reduce to produce rsx!                     |
-| Keyed Components        | ✅      | ✅     | advanced diffing with keys                            |
-| Web                     | ✅      | ✅     | renderer for web browser                              |
-| Desktop (webview)       | ✅      | ✅     | renderer for desktop                                  |
-| Shared State (Context)  | ✅      | ✅     | share state through the tree                          |
-| Hook                    | ✅      | ✅     | memory cells in components                            |
-| SSR                     | ✅      | ✅     | render directly to string                             |
-| Component Children      | ✅      | ✅     | cx.children() as a list of nodes                      |
-| Headless components     | ✅      | ✅     | components that don't return real elements            |
-| Fragments               | ✅      | ✅     | multiple elements without a real root                 |
-| Manual Props            | ✅      | ✅     | Manually pass in props with spread syntax             |
-| Controlled Inputs       | ✅      | ✅     | stateful wrappers around inputs                       |
-| CSS/Inline Styles       | ✅      | ✅     | syntax for inline styles/attribute groups             |
-| Custom elements         | ✅      | ✅     | Define new element primitives                         |
-| Suspense                | 🛠      | ✅     | schedule future render from future/promise            |
-| Cooperative Scheduling  | 🛠      | ✅     | Prioritize important events over non-important events |
-| NodeRef                 | 🛠      | ✅     | gain direct access to nodes [1]                       |
-| Fine-grained reactivity | 🛠      | ❓     | Skip diffing for fine-grain updates                   |
-| Compile-time correct    | ✅      | ❓     | Throw errors on invalid template layouts              |
-| Runs natively           | ✅      | ❓     | runs as a portable binary w/o a runtime (Node)        |
-| 1st class global state  | ✅      | ❓     | redux/recoil/mobx on top of context                   |
-| Subtree Memoization     | ✅      | ❓     | skip diffing static element subtrees                  |
-| Heuristic Engine        | ✅      | ❓     | track component memory usage to minimize allocations  |
+| Feature                 | Dioxus | React | Notes for Dioxus                                            |
+| ----------------------- | ------ | ----- | ----------------------------------------------------------- |
+| Conditional Rendering   | ✅      | ✅     | if/then to hide/show component                              |
+| Map, Iterator           | ✅      | ✅     | map/filter/reduce to produce rsx!                           |
+| Keyed Components        | ✅      | ✅     | advanced diffing with keys                                  |
+| Web                     | ✅      | ✅     | renderer for web browser                                    |
+| Desktop (webview)       | ✅      | ✅     | renderer for desktop                                        |
+| Shared State (Context)  | ✅      | ✅     | share state through the tree                                |
+| Hooks                   | ✅      | ✅     | memory cells in components                                  |
+| SSR                     | ✅      | ✅     | render directly to string                                   |
+| Component Children      | ✅      | ✅     | cx.children() as a list of nodes                            |
+| Headless components     | ✅      | ✅     | components that don't return real elements                  |
+| Fragments               | ✅      | ✅     | multiple elements without a real root                       |
+| Manual Props            | ✅      | ✅     | Manually pass in props with spread syntax                   |
+| Controlled Inputs       | ✅      | ✅     | stateful wrappers around inputs                             |
+| CSS/Inline Styles       | ✅      | ✅     | syntax for inline styles/attribute groups                   |
+| Custom elements         | ✅      | ✅     | Define new element primitives                               |
+| Suspense                | 🛠      | ✅     | schedule future render from future/promise                  |
+| Cooperative Scheduling  | 🛠      | ✅     | Prioritize important events over non-important events       |
+| Fine-grained reactivity | 🛠      | ❓     | Skip diffing for fine-grain updates                         |
+| Compile-time correct    | ✅      | ❓     | Throw errors on invalid template layouts                    |
+| Runs natively           | ✅      | ❓     | runs as a portable binary w/o a runtime (Node)              |
+| 1st class global state  | ✅      | ❓     | redux/recoil/mobx on top of context                         |
+| Subtree Memoization     | ✅      | ❓     | skip diffing static element subtrees                        |
+| Heuristic Engine        | 🛠      | ❓     | track component memory usage to minimize future allocations |
+| NodeRef                 | 🛠      | ✅     | gain direct access to nodes [1]                             |
 
 - [1] Currently blocked until we figure out a cross-platform way of exposing an imperative Node API.
 

+ 0 - 60
examples/compose.rs

@@ -1,60 +0,0 @@
-fn main() {}
-
-struct Title(String);
-
-struct Position([f32; 3]);
-
-struct Velocity([f32; 3]);
-
-type Batch<T> = fn(&mut T) -> ();
-
-static Atom: Batch<(Title, Position, Velocity)> = |_| {};
-
-enum VNode<'a> {
-    El(El<'a>),
-    Text(&'a str),
-    Fragment(&'a [VNode<'a>]),
-}
-struct El<'a> {
-    name: &'static str,
-    key: Option<&'a str>,
-    attrs: &'a [(&'static str, AttrType<'a>)],
-    children: &'a [El<'a>],
-}
-enum AttrType<'a> {
-    Numeric(usize),
-    Text(&'a str),
-}
-
-fn example() {
-    use AttrType::Numeric;
-    let el = El {
-        name: "div",
-        attrs: &[("type", Numeric(10)), ("type", Numeric(10))],
-        key: None,
-        children: &[],
-    };
-}
-
-use dioxus::prelude::bumpalo::Bump;
-trait IntoVnode {
-    fn into_vnode<'a>(self, b: &'a Bump) -> VNode<'a>;
-}
-
-impl<'a> IntoIterator for VNode<'a> {
-    type Item = VNode<'a>;
-    type IntoIter = std::iter::Once<VNode<'a>>;
-
-    #[inline]
-    fn into_iter(self) -> Self::IntoIter {
-        std::iter::once(self)
-    }
-}
-
-fn take_iterable<F: IntoVnode>(f: impl IntoIterator<Item = F>) {
-    let iter = f.into_iter();
-    let b = Bump::new();
-    for f in iter {
-        let v = f.into_vnode(&b);
-    }
-}

+ 3 - 3
examples/readme.rs

@@ -1,10 +1,10 @@
 //! Example: README.md showcase
 //!
-//! The example from the README.md
+//! The example from the README.md.
 
 use dioxus::prelude::*;
 fn main() {
-    dioxus::web::launch(App)
+    dioxus::desktop::launch(App, |c| c);
 }
 
 static App: FC<()> = |cx| {
@@ -12,7 +12,7 @@ static App: FC<()> = |cx| {
 
     cx.render(rsx! {
         div {
-            h1 { "Hifive counter: {count}" }
+            h1 { "High-Five counter: {count}" }
             button { onclick: move |_| count += 1, "Up high!" }
             button { onclick: move |_| count -= 1, "Down low!" }
         }

+ 0 - 2
examples/reference/webcomponents.rs

@@ -10,8 +10,6 @@
 //! We don't support building new webcomponents with Dioxus, however.
 //!
 
-use dioxus::{builder::ElementBuilder, prelude::NodeFactory};
-
 fn main() {}
 
 mod dioxus_elements {

+ 17 - 0
examples/ssr.rs

@@ -0,0 +1,17 @@
+use dioxus::prelude::*;
+use dioxus::ssr;
+
+fn main() {
+    let mut vdom = VirtualDom::new(App);
+    vdom.rebuild_in_place();
+    println!("{}", ssr::render_root(&vdom));
+}
+
+const App: FC<()> = |cx| {
+    cx.render(rsx!(
+        div {
+            h1 { "Title" }
+            p { "Body" }
+        }
+    ))
+};

+ 15 - 0
examples/testbed.rs

@@ -0,0 +1,15 @@
+use dioxus::prelude::*;
+
+fn main() {}
+
+static App: FC<()> = |cx| {
+    //
+    cx.render(rsx!(
+        div {
+            h1 {}
+        }
+    ))
+};
+
+#[test]
+fn blah() {}

+ 4 - 13
packages/core/examples/alternative.rs

@@ -1,24 +1,15 @@
 fn main() {}
 
+use dioxus::*;
 use dioxus_core as dioxus;
 use dioxus_core::prelude::*;
-mod dioxus_elements {
-    use super::*;
-    pub struct div;
-    impl DioxusElement for div {
-        const TAG_NAME: &'static str = "str";
-        const NAME_SPACE: Option<&'static str> = None;
-    }
-}
 
 static Example: FC<()> = |cx| {
-    let list = (0..10).map(|f| {
-        //
-        LazyNodes::new(move |f: NodeFactory| todo!())
-    });
+    let list = (0..10).map(|f| LazyNodes::new(move |f| todo!()));
+
     cx.render(LazyNodes::new(move |cx| {
         let bump = cx.bump();
-        dioxus_core::builder::ElementBuilder::new(&cx, "h1")
+        cx.raw_element("div")
             .children([
                 cx.text(format_args!("hello")),
                 cx.text(format_args!("hello")),

+ 1 - 0
packages/core/examples/borrowed.rs

@@ -7,6 +7,7 @@
 fn main() {}
 
 use dioxus_core::prelude::*;
+use dioxus_core::*;
 use std::rc::Rc;
 
 struct AppProps {

+ 4 - 1
packages/core/src/component.rs

@@ -44,6 +44,7 @@ pub fn fc_to_builder<T: Properties>(_: FC<T>) -> T::Builder {
     T::builder()
 }
 
+use crate::nodebuilder::LazyNodes;
 /// Create inline fragments
 ///
 /// Fragments capture a series of children without rendering extra nodes.
@@ -53,5 +54,7 @@ pub fn fc_to_builder<T: Properties>(_: FC<T>) -> T::Builder {
 use crate::prelude::*;
 #[allow(non_upper_case_globals, non_snake_case)]
 pub fn Fragment<'a>(cx: Context<'a, ()>) -> VNode<'a> {
-    cx.render(LazyNodes::new(move |f| f.fragment_from_iter(cx.children())))
+    cx.render(LazyNodes::new(move |f| {
+        f.fragment_from_iter(cx.children())
+    }))
 }

+ 2 - 2
packages/core/src/events.rs

@@ -125,8 +125,8 @@ pub mod on {
     use std::{fmt::Debug, ops::Deref, rc::Rc};
 
     use crate::{
-        builder::ElementBuilder,
-        builder::NodeFactory,
+        innerlude::ElementBuilder,
+        innerlude::NodeFactory,
         innerlude::{Attribute, Listener, RealDomNode, VNode},
     };
     use std::cell::Cell;

+ 15 - 30
packages/core/src/lib.rs

@@ -28,10 +28,6 @@ pub mod tasks;
 pub mod util;
 pub mod virtual_dom;
 
-pub mod builder {
-    pub use super::nodebuilder::*;
-}
-
 // types used internally that are important
 pub(crate) mod innerlude {
     pub use crate::bumpframe::*;
@@ -43,6 +39,7 @@ pub(crate) mod innerlude {
     pub use crate::nodebuilder::*;
     pub use crate::nodes::*;
     pub use crate::scope::*;
+    pub use crate::serialize::*;
     pub use crate::tasks::*;
     pub use crate::util::*;
     pub use crate::virtual_dom::*;
@@ -54,35 +51,23 @@ pub(crate) mod innerlude {
     pub use dioxus_core_macro::{html, rsx};
 }
 
-/// Re-export common types for ease of development use.
-/// Essential when working with the html! macro
+pub use crate::{
+    innerlude::{
+        DioxusElement, DomEdit, LazyNodes, NodeFactory, RealDom, RealDomNode, ScopeIdx, FC,
+    },
+    virtual_dom::VirtualDom,
+};
+
 pub mod prelude {
     pub use crate::component::{fc_to_builder, Fragment, Properties};
     pub use crate::context::Context;
-    use crate::nodes;
-    pub use crate::styles::{AsAttr, StyleBuilder};
-
-    pub use crate::util::RealDomNode;
-    pub use crate::virtual_dom::VirtualDom;
-    pub use nodes::*;
-
-    pub use crate::nodebuilder::LazyNodes;
-
-    pub use crate::nodebuilder::{DioxusElement, NodeFactory};
-    // pub use nodes::iterables::IterableNodes;
-    /// This type alias is an internal way of abstracting over the static functions that represent components.
-    pub use crate::innerlude::FC;
-
-    // expose our bumpalo type
-    pub use bumpalo;
-    pub use bumpalo::Bump;
-
-    // Re-export the FC macro
-    pub use crate::nodebuilder as builder;
-    // pub use dioxus_core_macro::fc;
-
+    pub use crate::innerlude::{LazyNodes, NodeFactory, FC};
+    pub use crate::nodebuilder::DioxusElement;
+    pub use crate::nodes::VNode;
+    pub use crate::VirtualDom;
     pub use dioxus_core_macro::{format_args_f, html, rsx, Props};
+}
 
-    pub use crate::diff::DiffMachine;
-    pub use crate::virtual_dom::ScopeIdx;
+pub mod exports {
+    // export important things here
 }

+ 15 - 2
packages/core/src/nodebuilder.rs

@@ -14,9 +14,8 @@ use bumpalo::Bump;
 
 use crate::{
     events::VirtualEvent,
-    innerlude::{Properties, RealDomNode, Scope, VComponent, VText, FC},
+    innerlude::{Properties, RealDomNode, Scope, VComponent, VFragment, VText, FC},
     nodes::{Attribute, Listener, NodeKey, VNode},
-    prelude::{VElement, VFragment},
 };
 
 /// A virtual DOM element builder.
@@ -647,6 +646,20 @@ impl<'a> NodeFactory<'a> {
         VNode::text(self.bump(), args)
     }
 
+    /// Create an element builder
+    pub fn raw_element<'b>(
+        &'b self,
+        tag: &'static str,
+    ) -> ElementBuilder<
+        'a,
+        'b,
+        bumpalo::collections::Vec<'a, Listener<'a>>,
+        bumpalo::collections::Vec<'a, Attribute<'a>>,
+        bumpalo::collections::Vec<'a, VNode<'a>>,
+    > {
+        ElementBuilder::new(self, tag)
+    }
+
     /// Create an element builder
     pub fn element<'b>(
         &'b self,

+ 1 - 1
packages/core/src/serialize.rs

@@ -7,7 +7,7 @@
 //!
 //!
 
-use crate::prelude::ScopeIdx;
+use crate::innerlude::ScopeIdx;
 use serde::{Deserialize, Serialize};
 
 /// A `DomEdit` represents a serialzied form of the VirtualDom's trait-based API. This allows streaming edits across the

+ 1 - 1
packages/core/src/tasks.rs

@@ -19,7 +19,7 @@ use std::{
 use futures_util::{Future, Stream, StreamExt};
 use slotmap::{DefaultKey, SlotMap};
 
-use crate::{events::EventTrigger, prelude::ScopeIdx};
+use crate::{events::EventTrigger, innerlude::ScopeIdx};
 
 pub type TaskSubmitter = Arc<dyn Fn(DTask)>;
 

+ 1 - 1
packages/html/src/lib.rs

@@ -7,7 +7,7 @@
 //! of the Rsx and Html macros. Each element comes with a substantial amount of documentation on how to best use it, hopefully
 //! making the development cycle quick.
 
-use dioxus_core::prelude::{DioxusElement, NodeFactory};
+use dioxus_core::{DioxusElement, NodeFactory};
 
 macro_rules! builder_constructors {
     ( $( $(#[$attr:meta])* $name:ident; )* ) => {

+ 34 - 11
packages/ssr/src/lib.rs

@@ -16,7 +16,7 @@ pub fn render_root(vdom: &VirtualDom) -> String {
 
 pub struct SsrConfig {
     // currently not supported - control if we indent the HTML output
-    _indent: bool,
+    indent: bool,
 
     // Control if elements are written onto a new line
     newline: bool,
@@ -30,7 +30,7 @@ pub struct SsrConfig {
 impl Default for SsrConfig {
     fn default() -> Self {
         Self {
-            _indent: false,
+            indent: false,
 
             newline: false,
             _skip_components: false,
@@ -68,10 +68,23 @@ impl<'a> TextRenderer<'a> {
         }
     }
 
-    fn html_render(&self, node: &VNode, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+    fn html_render(&self, node: &VNode, f: &mut std::fmt::Formatter, il: u16) -> std::fmt::Result {
         match node {
-            VNode::Text(text) => write!(f, "{}", text.text)?,
+            VNode::Text(text) => {
+                if self.cfg.indent {
+                    for _ in 0..il {
+                        write!(f, "    ")?;
+                    }
+                }
+                write!(f, "{}", text.text)?
+            }
             VNode::Element(el) => {
+                if self.cfg.indent {
+                    for _ in 0..il {
+                        write!(f, "    ")?;
+                    }
+                }
+
                 write!(f, "<{}", el.tag_name)?;
                 for attr in el.attributes {
                     write!(f, " {}=\"{}\"", attr.name, attr.value)?;
@@ -82,16 +95,26 @@ impl<'a> TextRenderer<'a> {
                 }
 
                 for child in el.children {
-                    self.html_render(child, f)?;
+                    self.html_render(child, f, il + 1)?;
                 }
-                match self.cfg.newline {
-                    true => write!(f, "\n</{}>", el.tag_name)?,
-                    false => write!(f, "</{}>", el.tag_name)?,
+
+                if self.cfg.newline {
+                    write!(f, "\n")?;
+                }
+                if self.cfg.indent {
+                    for _ in 0..il {
+                        write!(f, "    ")?;
+                    }
+                }
+
+                write!(f, "</{}>", el.tag_name)?;
+                if self.cfg.newline {
+                    write!(f, "\n")?;
                 }
             }
             VNode::Fragment(frag) => {
                 for child in frag.children {
-                    self.html_render(child, f)?;
+                    self.html_render(child, f, il + 1)?;
                 }
             }
             VNode::Component(vcomp) => {
@@ -105,7 +128,7 @@ impl<'a> TextRenderer<'a> {
                     .frames
                     .current_head_node();
 
-                self.html_render(new_node, f)?;
+                self.html_render(new_node, f, il + 1)?;
             }
             VNode::Suspended { .. } => todo!(),
         }
@@ -117,7 +140,7 @@ impl Display for TextRenderer<'_> {
     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
         let root = self.vdom.base_scope();
         let root_node = root.root();
-        self.html_render(root_node, f)
+        self.html_render(root_node, f, 0)
     }
 }
 

+ 0 - 28
packages/web/src/lib.rs

@@ -444,31 +444,3 @@ pub fn intern_cache() {
         wasm_bindgen::intern(s);
     }
 }
-
-#[cfg(test)]
-mod tests {
-    use std::env;
-
-    use super::*;
-    use dioxus::prelude::bumpalo;
-    use dioxus::prelude::format_args_f;
-    use dioxus_core as dioxus;
-    use dioxus_core::prelude::html;
-
-    fn simple_patch() {
-        env::set_var("RUST_LOG", "trace");
-        pretty_env_logger::init();
-        log::info!("Hello!");
-
-        wasm_bindgen_futures::spawn_local(WebsysRenderer::start(|cx| {
-            todo!()
-            // cx.render(html! {
-            //     <div>
-            //         "Hello world"
-            //         <button onclick={move |_| log::info!("button1 clicked!")}> "click me" </button>
-            //         <button onclick={move |_| log::info!("button2 clicked!")}> "click me" </button>
-            //     </div>
-            // })
-        }))
-    }
-}

+ 2 - 2
packages/web/src/new.rs

@@ -2,7 +2,7 @@ use std::{collections::HashMap, rc::Rc, sync::Arc};
 
 use dioxus_core::{
     events::{EventTrigger, VirtualEvent},
-    prelude::{RealDomNode, ScopeIdx},
+    RealDomNode, ScopeIdx,
 };
 use fxhash::FxHashMap;
 use slotmap::{DefaultKey, Key, KeyData};
@@ -192,7 +192,7 @@ impl<'a> dioxus_core::diff::RealDom<'a> for WebsysDom {
     fn new_event_listener(
         &mut self,
         event: &'static str,
-        scope: dioxus_core::prelude::ScopeIdx,
+        scope: ScopeIdx,
         _element_id: usize,
         real_id: RealDomNode,
     ) {

+ 2 - 4
packages/webview/src/dom.rs

@@ -1,8 +1,6 @@
 //! webview dom
 
-use dioxus_core as dioxus;
-use dioxus_core::prelude::*;
-use dioxus_core::{diff::RealDom, serialize::DomEdit, virtual_dom::VirtualDom};
+use dioxus_core::{DomEdit, RealDom, RealDomNode, ScopeIdx};
 use DomEdit::*;
 
 pub struct WebviewRegistry {}
@@ -80,7 +78,7 @@ impl<'bump> RealDom<'bump> for WebviewDom<'bump> {
     fn new_event_listener(
         &mut self,
         event: &'static str,
-        scope: dioxus_core::prelude::ScopeIdx,
+        scope: ScopeIdx,
         element_id: usize,
         realnode: RealDomNode,
     ) {

+ 16 - 47
src/lib.rs

@@ -165,60 +165,29 @@
 //!
 //! In reality, you'll want to integrate analytics, logging, crash-protection and more.
 
-pub mod prelude {
-    //! A glob import that includes helper types like FC, rsx!, html!, and required traits
-    pub use dioxus_core::prelude::*;
-    pub use dioxus_core_macro::fc;
-    pub use dioxus_hooks::*;
-    pub use dioxus_html as dioxus_elements;
-}
-// pub mod builder {
-//     // pub use dioxus_core::builder::*;
-// }
-pub use dioxus_core::builder;
-pub use dioxus_core::events;
-// pub mod events {
-//     // pub use dioxus_core::events::*;
-// }
 // Just a heads-up, the core functionality of dioxus rests in Dioxus-Core. This crate just wraps a bunch of utilities
 // together and exports their namespaces to something predicatble.
 #[cfg(feature = "core")]
-pub mod core {
-    //! Core functionality that includes the VirtualDOM, diffing, and Context APIs
+pub use dioxus_core as core;
 
-    // Re-export core completely
-    pub use dioxus_core::*;
-}
+#[cfg(feature = "core")]
+pub use dioxus_core::events;
 
-// Input elements work differently on different platforms.
-// This module helps abstract over Selects, TextInputs, TextAreas, Radios, etc for a cross-platform input experience
-pub mod inputs {
-    //! Cross-platform abstractions over user inputs
-}
 #[cfg(feature = "web")]
-pub mod web {
-    //! A web-sys based renderer for building fast and interactive web applications
-    use dioxus_core::prelude::{Properties, FC};
-    pub fn launch<P: Properties>(f: FC<P>) {}
-}
-#[cfg(feature = "ssr")]
-pub mod ssr {
-    //! A dedicated renderer for writing a Dioxus VirtualDOM to a string
-}
-#[cfg(feature = "ssr")]
-pub mod hooks {
-    //! Useful hooks like use_state, use_ref
-}
-#[cfg(feature = "ssr")]
-pub mod router {
-    //! A cross-platform router implementation
-}
+pub use dioxus_web as web;
+
 #[cfg(feature = "ssr")]
-pub mod testing {
-    //! Tools to make it easier to write tests for Dioxus components
-}
-#[cfg(feature = "atoms")]
-pub mod atoms {}
+pub use dioxus_ssr as ssr;
+
+#[cfg(feature = "hooks")]
+pub use dioxus_hooks as hooks;
 
 #[cfg(feature = "desktop")]
 pub use dioxus_webview as desktop;
+
+pub mod prelude {
+    //! A glob import that includes helper types like FC, rsx!, html!, and required traits
+    pub use dioxus_core::prelude::*;
+    pub use dioxus_hooks::*;
+    pub use dioxus_html as dioxus_elements;
+}