diff --git a/.vscode/spellright.dict b/.vscode/spellright.dict index e8ea0829..64826912 100644 --- a/.vscode/spellright.dict +++ b/.vscode/spellright.dict @@ -1 +1,3 @@ bearly +Clippy +tide_ssr diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b714553..70e300ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,39 @@ -# Initial Release +# Project: Live-View + + +# Project: Sanitization (TBD) +- [ ] (Macro) Clippy sanity for html macro +- [ ] (Macro) Error sanitization + +# Project: Examples +> Get *all* the examples +- [ ] (Examples) Tide example with templating + +# Project: State management +> Get some global state management installed with the hooks API + +# Project: Hooks + Context + Subscriptions (TBD) +> Implement a light-weight string renderer with basic caching +- [ ] Implement context object + + +# Project: Concurrency (TBD) +> Ensure the concurrency model works well, play with lifetimes to check if it can be multithreaded + halted + +# Project: Web_sys renderer (TBD) +- [ ] (Web) Web-sys renderer and web tests + +# Project: String Render (TBD) +> Implement a light-weight string renderer with basic caching +- [ ] (SSR) Implement stateful 3rd party string renderer +- [ ] (Macro) Make VText nodes automatically capture and format IE allow "Text is {blah}" in place of {format!("Text is {}",blah)} + +# Project: Initial Release (TBD) +> Get the initial VDom + Event System + Patching + Diffing + Component framework up and running +- [x] (Core) Migrate virtual node into new VNode type +- [ ] (Core) Arena allocate VNodes +- [ ] (Core) Allow VNodes to borrow arena contents - [ ] (Macro) Tweak event syntax to not be dependent on wasm32 target (just return regular closures) - [ ] (Macro) Tweak component syntax to accept a new custom element - [ ] (Core) Introduce the VDOM and patch API for 3rd party renderers -- [ ] (Web) Web-sys renderer and web tests -- [ ] (Examples) Tide example with templating + diff --git a/Cargo.toml b/Cargo.toml index 1ab73554..996c9787 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,4 +15,5 @@ members = [ "packages/html-macro-test", "packages/virtual-dom-rs", "packages/virtual-node", + "examples", ] diff --git a/README.md b/README.md index 4156ee2a..95ebc5b4 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ fn Example(ctx: &Context<{ name: String }>) -> VNode { static Example: FC<{ name: String }> = |ctx| html! {
"Hello {:?name}!"
}; ``` -The final output of components must be a tree of VNodes. We provide an html macro for using JSX-style syntax to write these, though, you could use any macro, dsl, or templating engine. Work is being done on a terra template processor for existing templates. +The final output of components must be a tree of VNodes. We provide an html macro for using JSX-style syntax to write these, though, you could use any macro, DSL, or templating engine. Work is being done on a terra template processor for existing templates. ## Features @@ -58,32 +58,11 @@ async fn user_data(ctx: &Context<()>) -> VNode { Asynchronous components are powerful but can also be easy to misuse as they pause rendering for the component and its children. Refer to the concurrent guide for information on how to best use async components. -## Example -- Isomorphic: serve a server-rendered webapp using Tide +## Examples +We use `diopack` to build and test apps. This can run examples, tests, build web workers, launch development servers, bundle, and more. It's general purpose, but currently very tailored to Dioxus for liveview and bundling. Alternatively, `Trunk` works but can't run examples. + +- tide_ssr: Handle an HTTP request and return an html body using the html! macro. ## Documentation -| Chapter | Description | -| -------------- | ------------------------------------------ | -| 1-hello-world | Intro to Dioxus | -| 2-utilities | Tools to make writing apps easier | -| 3-hello-world | Html + functional_component macro | -| 4-hello-world | Renderer + event integration using web_sys | -| 5-hello-world | Virtual DOM, patching/diffing | -| 6-hello-world | Standard bundle of useful hooks | -| 7-hello-world | Html + functional_component macro | -| 8-hello-world | Renderer + event integration using web_sys | -| 9-hello-world | Renderer + event integration using web_sys | -| 10-hello-world | Renderer + event integration using web_sys | - -## Packages -| Package | Use | -| --------- | ------------------------------------------ | -| core | Virtual DOM, patching/diffing | -| hooks | Standard bundle of useful hooks | -| macro | Html + functional_component macro | -| web | Renderer + event integration using web_sys | -| live-view | Dedicated isomorphic framework | -| recoil | Data-flow-graph state management | -| redux | Reducer-style state management | -| bearly | Simple and idiomatic state management | +We have a pretty robust diff --git a/docs/0-index.md b/docs/0-index.md new file mode 100644 index 00000000..8c31b2a5 --- /dev/null +++ b/docs/0-index.md @@ -0,0 +1,32 @@ +# Dioxus Chapter 0 - Intro + Index + +## Guides +------------------ +| Chapter | Description | +| -------------- | ------------------------------------------ | +| 1-hello-world | Intro to Dioxus | +| 2-utilities | Tools to make writing apps easier | +| 3-hello-world | Html + functional_component macro | +| 4-hello-world | Renderer + event integration using web_sys | +| 5-hello-world | Virtual DOM, patching/diffing | +| 6-hello-world | Standard bundle of useful hooks | +| 7-hello-world | Html + functional_component macro | +| 8-hello-world | Renderer + event integration using web_sys | +| 9-hello-world | Renderer + event integration using web_sys | +| 10-hello-world | Renderer + event integration using web_sys | + + +## Development +------------------ +| Package | Use | +| ------- | ------------------------------------------------ | +| full | Batteries-included entrypoint with feature flags | +| core | Virtual DOM, diffing, patching, and events | +| hooks | Standard hooks | +| macro | Html + functional_component macro | +| web | Renderer + event integration using web_sys | +| live | Dedicated isomorphic framework | +| recoil | Data-flow-graph state management | +| redux | Reducer-style state management | +| bearly | Simple and idiomatic state management | + diff --git a/examples/Cargo.toml b/examples/Cargo.toml new file mode 100644 index 00000000..e70ad1e3 --- /dev/null +++ b/examples/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "dioxus-examples" +version = "0.0.0" +authors = ["Jonathan Kelley "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +fern = { vesion = "0.6.0", features = ["colored"] } +log = "0.4.13" +dioxus-core = { path = "../packages/core" } +rand = "0.8.2" + + +[dev-dependencies] +async-std = { version = "1.9.0", features = ["attributes"] } +tide = { version = "0.15.0" } + + +[lib] +path = "common.rs" + +[[example]] +path = "hello.rs" +name = "hello" + +[[example]] +path = "tide_ssr.rs" +name = "tide_ssr" diff --git a/examples/common.rs b/examples/common.rs new file mode 100644 index 00000000..73a3bdfb --- /dev/null +++ b/examples/common.rs @@ -0,0 +1,52 @@ +//! Common utilities for integration examples + +pub mod logger { + + use fern::colors::{Color, ColoredLevelConfig}; + use log::debug; + + pub fn set_up_logging(bin_name: &'static str) { + // configure colors for the whole line + let colors_line = ColoredLevelConfig::new() + .error(Color::Red) + .warn(Color::Yellow) + // we actually don't need to specify the color for debug and info, they are white by default + .info(Color::White) + .debug(Color::White) + // depending on the terminals color scheme, this is the same as the background color + .trace(Color::BrightBlack); + + // configure colors for the name of the level. + // since almost all of them are the same as the color for the whole line, we + // just clone `colors_line` and overwrite our changes + let colors_level = colors_line.clone().info(Color::Green); + // here we set up our fern Dispatch + fern::Dispatch::new() + .format(move |out, message, record| { + out.finish(format_args!( + "{color_line}[{level}{color_line}] {message}\x1B[0m", + color_line = format_args!( + "\x1B[{}m", + colors_line.get_color(&record.level()).to_fg_str() + ), + level = colors_level.color(record.level()), + message = message, + )); + }) + // set the default log level. to filter out verbose log messages from dependencies, set + // this to Warn and overwrite the log level for your crate. + .level(log::LevelFilter::Warn) + // change log levels for individual modules. Note: This looks for the record's target + // field which defaults to the module path but can be overwritten with the `target` + // parameter: + // `info!(target="special_target", "This log message is about special_target");` + .level_for(bin_name, log::LevelFilter::Info) + // .level_for("pretty_colored", log::LevelFilter::Trace) + // output to stdout + .chain(std::io::stdout()) + .apply() + .unwrap(); + + debug!("finished setting up logging! yay!"); + } +} diff --git a/examples/hello.rs b/examples/hello.rs new file mode 100644 index 00000000..bdce8b29 --- /dev/null +++ b/examples/hello.rs @@ -0,0 +1,9 @@ +fn main() { + println!("Hello world!"); + println!("Hello world!"); + println!("Hello world!"); + println!("Hello world!"); + println!("Hello world!"); + println!("Hello world!"); + println!("Hello world!"); +} diff --git a/examples/tide_ssr.rs b/examples/tide_ssr.rs new file mode 100644 index 00000000..9147ea44 --- /dev/null +++ b/examples/tide_ssr.rs @@ -0,0 +1,99 @@ +//! This demo shows how to use the to_string utility on VNodes to convert them into valid HTML. +//! You can use the html! macro to craft webpages generated by the server on-the-fly. +//! +//! Server-side-renderered webpages are a great use of Rust's async story, where servers can handle +//! thousands of simultaneous clients on minimal hardware. + +use dioxus_core::prelude::*; +use tide::{Request, Response}; + +#[async_std::main] +async fn main() -> Result<(), std::io::Error> { + dioxus_examples::logger::set_up_logging("tide_ssr"); + + // Build the API + let mut app = tide::new(); + app.at("/fib/:n").get(fibsum); + + // Launch the server + let addr = "127.0.0.1:8080"; + log::info!("App is ready at {}", addr); + log::info!("Navigate to an fibonacci number, like so http://localhost:8080/fib/21"); + app.listen(addr).await?; + + Ok(()) +} + +/// Calculate the fibonacci number for a given request input +async fn fibsum(req: Request<()>) -> tide::Result { + use std::time::Instant; + let n: usize = req.param("n")?.parse().unwrap_or(0); + + fn fib(n: usize) -> usize { + if n == 0 || n == 1 { + n + } else { + fib(n - 1) + fib(n - 2) + } + } + + // Start a stopwatch + // Compute the nth number in the fibonacci sequence + // Stop the stopwatch + let start = Instant::now(); + let fib_n = fib(n); + let duration = start.elapsed().as_nanos(); + + let mut rng = rand::thread_rng(); + use rand::Rng; + let other_fib_to_try = rng.gen_range(1..42); + + let nodes = html! { + + + + + + + + + +
+
+
+ // Title +
+ {format!("Fibonacci Calculator: n = {}",n)} +
+ + // Subtext / description +
+ {format!("Calculated in {} nanoseconds",duration)} +
+ +
+ // Main number +
+ {format!("{}",fib_n)} +
+ +
+ +
+
+
+ + + + }; + + Ok(Response::builder(203) + .body(nodes.to_string()) + .header("custom-header", "value") + .content_type(tide::http::mime::HTML) + .build()) +} diff --git a/packages/core/Cargo.toml b/packages/core/Cargo.toml index a14e1b6a..18005fa5 100644 --- a/packages/core/Cargo.toml +++ b/packages/core/Cargo.toml @@ -8,10 +8,12 @@ edition = "2018" [dependencies] generational-arena = "0.2.8" -typed-arena = "2.0.1" -virtual-dom-rs = { path = "../virtual-dom-rs" } -virtual-node = { path = "../virtual-node" } html-macro = { path = "../html-macro" } once_cell = "1.5.2" + + # web-sys = "0.3.46" # js-sys = "0.3.46" +# typed-arena = "2.0.1" +# virtual-dom-rs = { path = "../virtual-dom-rs" } +# virtual-node = { path = "../virtual-node" } diff --git a/packages/core/examples/simple.rs b/packages/core/examples/simple.rs index f9d5b459..ea2b0dde 100644 --- a/packages/core/examples/simple.rs +++ b/packages/core/examples/simple.rs @@ -1,7 +1,7 @@ use std::future::Future; use dioxus_core::{component::AnyContext, prelude::*}; -use virtual_dom_rs::Closure; +// use virtual_dom_rs::Closure; // Stop-gap while developing // Need to update the macro @@ -27,9 +27,18 @@ fn root(ctx: &mut AnyContext) -> VNode { // or a manually crated vnode { let mut node_0 = VNode::element("div"); + { + if let Some(ref mut element_node) = node_0.as_velement_mut() { + // element_node.attrs.insert("blah", "blah"); + // element_node.children.extend(node_0.into_iter()); + } + } + let mut node_1: IterableNodes = ("Hello world!").into(); node_1.first().insert_space_before_text(); let mut node_2 = VNode::element("button"); + + let node_3 = VNode::Component(VComponent {}); { // let closure = Closure::wrap(Box::new(|_| {}) as Box); // let closure_rc = std::rc::Rc::new(closure); diff --git a/packages/core/src/lib.rs b/packages/core/src/lib.rs index 41ca4da0..6462f0e9 100644 --- a/packages/core/src/lib.rs +++ b/packages/core/src/lib.rs @@ -25,6 +25,9 @@ pub mod prelude { pub use nodes::iterables::IterableNodes; pub use nodes::*; + // hack "virtualnode" + pub type VirtualNode = VNode; + // Re-export from the macro crate pub use html_macro::html; } @@ -262,6 +265,8 @@ pub mod nodes { /// HTML attributes such as id, class, style, etc pub attrs: HashMap, + // TODO: @JON Get this to not heap allocate, but rather borrow + // pub attrs: HashMap<&'static str, &'static str>, // TODO @Jon, re-enable "events" // diff --git a/packages/ssr/Cargo.toml b/packages/ssr/Cargo.toml new file mode 100644 index 00000000..1d0c4142 --- /dev/null +++ b/packages/ssr/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "dioxus-ssr" +version = "0.0.0" +authors = ["Jonathan Kelley "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] \ No newline at end of file diff --git a/packages/ssr/src/lib.rs b/packages/ssr/src/lib.rs new file mode 100644 index 00000000..31e1bb20 --- /dev/null +++ b/packages/ssr/src/lib.rs @@ -0,0 +1,7 @@ +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +}