diff --git a/assets/dioxus/docsite.js b/assets/dioxus/docsite.js index d12fd5737..63a1c6428 100644 --- a/assets/dioxus/docsite.js +++ b/assets/dioxus/docsite.js @@ -275,7 +275,7 @@ function __wbg_adapter_48(arg0, arg1, arg2) { try { _assertNum(arg0); _assertNum(arg1); - wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hde911a6e75dcdc70(arg0, arg1, addBorrowedObject(arg2)); + wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h97d6720a74706a47(arg0, arg1, addBorrowedObject(arg2)); } finally { heap[stack_pointer++] = undefined; } @@ -284,7 +284,7 @@ function __wbg_adapter_48(arg0, arg1, arg2) { function __wbg_adapter_51(arg0, arg1) { _assertNum(arg0); _assertNum(arg1); - wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h72b9046645733a63(arg0, arg1); + wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__he2e688f790950d0a(arg0, arg1); } function makeClosure(arg0, arg1, dtor, f) { @@ -311,32 +311,32 @@ function makeClosure(arg0, arg1, dtor, f) { function __wbg_adapter_54(arg0, arg1, arg2) { _assertNum(arg0); _assertNum(arg1); - wasm._dyn_core__ops__function__Fn__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hb0f44eaff47b8128(arg0, arg1, addHeapObject(arg2)); + wasm._dyn_core__ops__function__Fn__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h636d870e09540d00(arg0, arg1, addHeapObject(arg2)); } function __wbg_adapter_57(arg0, arg1) { _assertNum(arg0); _assertNum(arg1); - wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h7ca6d453aefdf7f4(arg0, arg1); + wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hf8ff19922b96b6b0(arg0, arg1); } function __wbg_adapter_60(arg0, arg1, arg2) { _assertNum(arg0); _assertNum(arg1); - wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h1f5521e1a4df9ba4(arg0, arg1, addHeapObject(arg2)); + wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h20e8942ce11bde76(arg0, arg1, addHeapObject(arg2)); } function __wbg_adapter_63(arg0, arg1, arg2) { _assertNum(arg0); _assertNum(arg1); - wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h390745bdf35536ce(arg0, arg1, addHeapObject(arg2)); + wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h00cef57c0e55f896(arg0, arg1, addHeapObject(arg2)); } function __wbg_adapter_66(arg0, arg1, arg2) { try { _assertNum(arg0); _assertNum(arg1); - wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hd135f337b4766aa7(arg0, arg1, addBorrowedObject(arg2)); + wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hb43526dea1bbe3b1(arg0, arg1, addBorrowedObject(arg2)); } finally { heap[stack_pointer++] = undefined; } @@ -556,6 +556,11 @@ imports.wbg.__wbg_fetch_381efb5e862610fa = function() { return logError(function const ret = fetch(getObject(arg0)); return addHeapObject(ret); }, arguments) }; +imports.wbg.__wbindgen_is_string = function(arg0) { + const ret = typeof(getObject(arg0)) === 'string'; + _assertBoolean(ret); + return ret; +}; imports.wbg.__wbindgen_number_new = function(arg0) { const ret = arg0; return addHeapObject(ret); @@ -578,11 +583,6 @@ imports.wbg.__wbindgen_cb_drop = function(arg0) { _assertBoolean(ret); return ret; }; -imports.wbg.__wbindgen_is_string = function(arg0) { - const ret = typeof(getObject(arg0)) === 'string'; - _assertBoolean(ret); - return ret; -}; imports.wbg.__wbindgen_jsval_loose_eq = function(arg0, arg1) { const ret = getObject(arg0) == getObject(arg1); _assertBoolean(ret); @@ -1515,24 +1515,24 @@ imports.wbg.__wbindgen_closure_wrapper574 = function() { return logError(functio const ret = makeMutClosure(arg0, arg1, 107, __wbg_adapter_51); return addHeapObject(ret); }, arguments) }; -imports.wbg.__wbindgen_closure_wrapper5893 = function() { return logError(function (arg0, arg1, arg2) { - const ret = makeClosure(arg0, arg1, 1652, __wbg_adapter_54); +imports.wbg.__wbindgen_closure_wrapper5915 = function() { return logError(function (arg0, arg1, arg2) { + const ret = makeClosure(arg0, arg1, 1691, __wbg_adapter_54); return addHeapObject(ret); }, arguments) }; -imports.wbg.__wbindgen_closure_wrapper5952 = function() { return logError(function (arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 1674, __wbg_adapter_57); +imports.wbg.__wbindgen_closure_wrapper5976 = function() { return logError(function (arg0, arg1, arg2) { + const ret = makeMutClosure(arg0, arg1, 1699, __wbg_adapter_57); return addHeapObject(ret); }, arguments) }; -imports.wbg.__wbindgen_closure_wrapper5975 = function() { return logError(function (arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 1682, __wbg_adapter_60); +imports.wbg.__wbindgen_closure_wrapper6000 = function() { return logError(function (arg0, arg1, arg2) { + const ret = makeMutClosure(arg0, arg1, 1707, __wbg_adapter_60); return addHeapObject(ret); }, arguments) }; -imports.wbg.__wbindgen_closure_wrapper5991 = function() { return logError(function (arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 1693, __wbg_adapter_63); +imports.wbg.__wbindgen_closure_wrapper6020 = function() { return logError(function (arg0, arg1, arg2) { + const ret = makeMutClosure(arg0, arg1, 1718, __wbg_adapter_63); return addHeapObject(ret); }, arguments) }; -imports.wbg.__wbindgen_closure_wrapper6232 = function() { return logError(function (arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 1772, __wbg_adapter_66); +imports.wbg.__wbindgen_closure_wrapper6265 = function() { return logError(function (arg0, arg1, arg2) { + const ret = makeMutClosure(arg0, arg1, 1797, __wbg_adapter_66); return addHeapObject(ret); }, arguments) }; imports['./snippets/dioxus-interpreter-js-603636eeca72cf05/inline0.js'] = __wbg_star0; diff --git a/assets/dioxus/docsite_bg.wasm b/assets/dioxus/docsite_bg.wasm index c38be0ff2..c0fbd6d9f 100644 Binary files a/assets/dioxus/docsite_bg.wasm and b/assets/dioxus/docsite_bg.wasm differ diff --git a/assets/dioxus/snippets/dioxus-interpreter-js-603636eeca72cf05/inline0.js b/assets/dioxus/snippets/dioxus-interpreter-js-603636eeca72cf05/inline0.js index ae773e21c..539a1512d 100644 --- a/assets/dioxus/snippets/dioxus-interpreter-js-603636eeca72cf05/inline0.js +++ b/assets/dioxus/snippets/dioxus-interpreter-js-603636eeca72cf05/inline0.js @@ -163,7 +163,19 @@ let m,p,ls,d,t,op,i,e,z,metaflags; function truthy(val) { return val === "true" || val === true; } - let u32buf,u32bufp;let s = "";let lsp,sp,sl; let c = new TextDecoder();const evt = []; + const ns_cache = []; + let ns_cache_tmp1, ns_cache_tmp2; + function get_ns_cache() { + ns_cache_tmp2 = u8buf[u8bufp++]; + if(ns_cache_tmp2 & 128){ + ns_cache_tmp1=s.substring(sp,sp+=u8buf[u8bufp++]); + ns_cache[ns_cache_tmp2&4294967167]=ns_cache_tmp1; + return ns_cache_tmp1; + } + else{ + return ns_cache[ns_cache_tmp2&4294967167]; + } + }let s = "";let lsp,sp,sl; let c = new TextDecoder();let u32buf,u32bufp;let u8buf,u8bufp;const evt = []; let evt_tmp1, evt_tmp2; function get_evt() { evt_tmp2 = u8buf[u8bufp++]; @@ -175,7 +187,7 @@ let m,p,ls,d,t,op,i,e,z,metaflags; else{ return evt[evt_tmp2&4294967167]; } - }let u8buf,u8bufp;const attr = []; + }const attr = []; let attr_tmp1, attr_tmp2; function get_attr() { attr_tmp2 = u8buf[u8bufp++]; @@ -187,20 +199,8 @@ let m,p,ls,d,t,op,i,e,z,metaflags; else{ return attr[attr_tmp2&4294967167]; } - }const ns_cache = []; - let ns_cache_tmp1, ns_cache_tmp2; - function get_ns_cache() { - ns_cache_tmp2 = u8buf[u8bufp++]; - if(ns_cache_tmp2 & 128){ - ns_cache_tmp1=s.substring(sp,sp+=u8buf[u8bufp++]); - ns_cache[ns_cache_tmp2&4294967167]=ns_cache_tmp1; - return ns_cache_tmp1; - } - else{ - return ns_cache[ns_cache_tmp2&4294967167]; - } } - let id,field,ns,bubbles,len,value,event_name,ptr; + let id,ns,event_name,ptr,len,field,value,bubbles; export function create(r){ d=r; } @@ -213,10 +213,7 @@ let m,p,ls,d,t,op,i,e,z,metaflags; ls=m.getUint32(d+12*4,true); } p=ls; - if ((metaflags>>>3)&1){ - u32buf=new Uint32Array(m.buffer,m.getUint32(d+3*4,true)) - } - u32bufp=0;if (metaflags&1){ + if (metaflags&1){ lsp = m.getUint32(d+1*4,true); } if ((metaflags>>>2)&1) { @@ -242,7 +239,10 @@ let m,p,ls,d,t,op,i,e,z,metaflags; s = c.decode(new DataView(m.buffer, lsp, sl)); } } - sp=0;if ((metaflags>>>5)&1){ + sp=0;if ((metaflags>>>3)&1){ + u32buf=new Uint32Array(m.buffer,m.getUint32(d+3*4,true)) + } + u32bufp=0;if ((metaflags>>>5)&1){ u8buf=new Uint8Array(m.buffer,m.getUint32(d+5*4,true)) } u8bufp=0; diff --git a/learn/0.4/CLI/configure/index.html b/learn/0.4/CLI/configure/index.html index c29a10ab6..0f14b03de 100644 --- a/learn/0.4/CLI/configure/index.html +++ b/learn/0.4/CLI/configure/index.html @@ -253,7 +253,7 @@ [[web.proxy]] backend = "http://localhost:8000/api/" - + +

Finally, serve your project with dx serve!The CLI will tell you the address it is serving on, along with additional info such as code warnings.

+

Introduction

The ✨Dioxus CLI✨ is a tool to get Dioxus projects off the ground.

There's no documentation for commands here,but you can see all commands using dx --help once you've installed the CLI!Furthermore, you can run dx <command> --help to get help with a specific command.

Features

  • Build and pack a Dioxus project.
  • Format rsx code.
  • Hot Reload for web platform.
  • Create a Dioxus project from a template repository.
  • And more!
+

This will download the CLI from the master branch,and install it in Cargo's global binary directory (~/.cargo/bin/ by default).

Run dx --help for a list of all the available commands.Furthermore, you can run dx <command> --help to get help with a specific command.

+

Overall Goals

This document outlines some of the overall goals for Dioxus. These goals are not set in stone, but they represent general guidelines for the project.

The goal of Dioxus is to make it easy to build cross-platform applications that scale.

Cross-Platform

Dioxus is designed to be cross-platform by default. This means that it should be easy to build applications that run on the web, desktop, and mobile. However, Dioxus should also be flexible enough to allow users to opt into platform-specific features when needed. The use_eval is one example of this. By default, Dioxus does not assume that the platform supports JavaScript, but it does provide a hook that allows users to opt into JavaScript when needed.

Performance

As Dioxus applications grow, they should remain relatively performant without the need for manual optimizations. There will be cases where manual optimizations are needed, but Dioxus should try to make these cases as rare as possible.

One of the benefits of the core architecture of Dioxus is that it delivers reasonable performance even when components are rerendered often. It is based on a Virtual Dom which performs diffing which should prevent unnecessary re-renders even when large parts of the component tree are rerun. On top of this, Dioxus groups static parts of the RSX tree together to skip diffing them entirely.

Type Safety

As teams grow, the Type safety of Rust is a huge advantage. Dioxus should leverage this advantage to make it easy to build applications with large teams.

To take full advantage of Rust's type system, Dioxus should try to avoid exposing public Any types and string-ly typed APIs where possible.

Developer Experience

Dioxus should be easy to learn and ergonomic to use.

  • The API of Dioxus attempts to remain close to React's API where possible. This makes it easier for people to learn Dioxus if they already know React

  • We can avoid the tradeoff between simplicity and flexibility by providing multiple layers of API: One for the very common use case, one for low-level control

    • Hooks: the hooks crate has the most common use cases, but cx.hook provides a way to access the underlying persistent reference if needed.
    • The builder pattern in platform Configs: The builder pattern is used to default to the most common use case, but users can change the defaults if needed.
  • Documentation:

    • All public APIs should have rust documentation
    • Examples should be provided for all public features. These examples both serve as documentation and testing. They are checked by CI to ensure that they continue to compile
    • The most common workflows should be documented in the guide
+ +

Project Structure

There are many packages in the Dioxus organization. This document will help you understand the purpose of each package and how they fit together.

Renderers

  • Desktop: A Render that Runs Dioxus applications natively, but renders them with the system webview
  • Mobile: A Render that Runs Dioxus applications natively, but renders them with the system webview. This is currently a copy of the desktop render
  • Web: Renders Dioxus applications in the browser by compiling to WASM and manipulating the DOM
  • Liveview: A Render that Runs on the server, and renders using a websocket proxy in the browser
  • Rink: A Renderer that renders a HTML-like tree into a terminal
  • TUI: A Renderer that uses Rink to render a Dioxus application in a terminal
  • Blitz-Core: An experimental native renderer that renders a HTML-like tree using WGPU.
  • Blitz: An experimental native renderer that uses Blitz-Core to render a Dioxus application using WGPU.
  • SSR: A Render that Runs Dioxus applications on the server, and renders them to HTML

State Management/Hooks

  • Hooks: A collection of common hooks for Dioxus applications
  • Signals: A experimental state management library for Dioxus applications. This currently contains a Copy version of UseRef
  • Dioxus STD: A collection of platform agnostic hooks to interact with system interfaces (The clipboard, camera, etc.).
  • Fermi: A global state management library for Dioxus applications.Router: A client-side router for Dioxus applications

Core utilities

  • core: The core virtual dom implementation every Dioxus application uses
  • RSX: The core parsing for RSX used for hot reloading, autoformatting, and the macro
  • core-macro: The rsx! macro used to write Dioxus applications. (This is a wrapper over the RSX crate)
  • HTML macro: A html-like alternative to the RSX macro

Native Renderer Utilities

Web renderer tooling

  • HTML: defines html specific elements, events, and attributes
  • Interpreter: defines browser bindings used by the web and desktop renderers

Developer tooling

  • hot-reload: Macro that uses the RSX crate to hot reload static parts of any rsx! macro. This macro works with any non-web renderer with an integration
  • autofmt: Formats RSX code
  • rsx-rosetta: Handles conversion between HTML and RSX
  • CLI: A Command Line Interface and VSCode extension to assist with Dioxus usage
+

Roadmap & Feature-set

This feature set and roadmap can help you decide if what Dioxus can do today works for you.

If a feature that you need doesn't exist or you want to contribute to projects on the roadmap, feel free to get involved by joining the discord.

Generally, here's the status of each platform:

  • Web: Dioxus is a great choice for pure web-apps – especially for CRUD/complex apps. However, it does lack the ecosystem of React, so you might be missing a component library or some useful hook.

  • SSR: Dioxus is a great choice for pre-rendering, hydration, and rendering HTML on a web endpoint. Be warned – the VirtualDom is not (currently) Send + Sync.

  • Desktop: You can build very competent single-window desktop apps right now. However, multi-window apps require support from Dioxus core and are not ready.

  • Mobile: Mobile support is very young. You'll be figuring things out as you go and there are not many support crates for peripherals.

  • LiveView: LiveView support is very young. You'll be figuring things out as you go. Thankfully, none of it is too hard and any work can be upstreamed into Dioxus.

Features


FeatureStatusDescription
Conditional Renderingxif/then to hide/show component
Map, Iteratorxmap/filter/reduce to produce rsx!
Keyed Componentsxadvanced diffing with keys
Webxrenderer for web browser
Desktop (webview)xrenderer for desktop
Shared State (Context)xshare state through the tree
Hooksxmemory cells in components
SSRxrender directly to string
Component Childrenxcx.children() as a list of nodes
Headless componentsxcomponents that don't return real elements
Fragmentsxmultiple elements without a real root
Manual PropsxManually pass in props with spread syntax
Controlled Inputsxstateful wrappers around inputs
CSS/Inline Stylesxsyntax for inline styles/attribute groups
Custom elementsxDefine new element primitives
Suspensexschedule future render from future/promise
Integrated error handlingxGracefully handle errors with ? syntax
NodeRefxgain direct access to nodes
Re-hydrationxPre-render to HTML to speed up first contentful paint
Jank-Free RenderingxLarge diffs are segmented across frames for silky-smooth transitions
EffectsxRun effects after a component has been committed to render
Portals*Render nodes outside of the traditional tree structure
Cooperative Scheduling*Prioritize important events over non-important events
Server Components*Hybrid components for SPA and Server
Bundle SplittingiEfficiently and asynchronously load the app
Lazy ComponentsiDynamically load the new components as the page is loaded
1st class global statexredux/recoil/mobx on top of context
Runs nativelyxruns as a portable binary w/o a runtime (Node)
Subtree Memoizationxskip diffing static element subtrees
High-efficiency templatesxrsx! calls are translated to templates on the DOM's side
Compile-time correctxThrow errors on invalid template layouts
Heuristic Enginextrack component memory usage to minimize future allocations
Fine-grained reactivityiSkip diffing for fine-grain updates
  • x = implemented and working
    • = actively being worked on
  • i = not yet implemented or being worked on

Roadmap

These Features are planned for the future of Dioxus:

Core

  • [x] Release of Dioxus Core
  • [x] Upgrade documentation to include more theory and be more comprehensive
  • [x] Support for HTML-side templates for lightning-fast dom manipulation
  • [ ] Support for multiple renderers for same virtualdom (subtrees)
  • [ ] Support for ThreadSafe (Send + Sync)
  • [ ] Support for Portals

SSR

  • [x] SSR Support + Hydration
  • [ ] Integrated suspense support for SSR

Desktop

  • [ ] Declarative window management
  • [ ] Templates for building/bundling
  • [ ] Access to Canvas/WebGL context natively

Mobile

  • [ ] Mobile standard library
    • [ ] GPS
    • [ ] Camera
    • [ ] filesystem
    • [ ] Biometrics
    • [ ] WiFi
    • [ ] Bluetooth
    • [ ] Notifications
    • [ ] Clipboard
  • [ ] Animations

Bundling (CLI)

  • [x] Translation from HTML into RSX
  • [x] Dev server
  • [x] Live reload
  • [x] Translation from JSX into RSX
  • [ ] Hot module replacement
  • [ ] Code splitting
  • [ ] Asset macros
  • [ ] Css pipeline
  • [ ] Image pipeline

Essential hooks

  • [x] Router
  • [x] Global state management
  • [ ] Resize observer

Work in Progress

Build Tool

We are currently working on our own build tool called Dioxus CLI which will support:

  • an interactive TUI
  • on-the-fly reconfiguration
  • hot CSS reloading
  • two-way data binding between browser and source code
  • an interpreter for rsx!
  • ability to publish to github/netlify/vercel
  • bundling for iOS/Desktop/etc

Server Component Support

While not currently fully implemented, the expectation is that LiveView apps can be a hybrid between Wasm and server-rendered where only portions of a page are "live" and the rest of the page is either server-rendered, statically generated, or handled by the host SPA.

Native rendering

We are currently working on a native renderer for Dioxus using WGPU called Blitz. This will allow you to build apps that are rendered natively for iOS, Android, and Desktop.

+

What is a slab?

A slab acts like a hashmap with integer keys if you don't care about the value of the keys. It is internally backed by a dense vector which makes it more efficient than a hashmap. When you insert a value into a slab, it returns an integer key that you can use to retrieve the value later.

How does Dioxus use slabs?

Dioxus uses "synchronized slabs" to communicate between the renderer and the VDOM. When a node is created in the Virtual DOM, an (elementId, mutation) pair is passed to the renderer to identify that node, which the renderer will then render in actual DOM. These ids are also used by the Virtual Dom to reference that node in future mutations, like setting an attribute on a node or removing a node. When the renderer sends an event to the Virtual Dom, it sends the ElementId of the node that the event was triggered on. The Virtual DOM uses this id to find that node in the slab and then run the necessary event handlers.

The virtual DOM is a tree of scopes. A new Scope is created for every component when it is first rendered and recycled when the component is unmounted.

Scopes serve three main purposes:

  1. They store the state of hooks used by the component
  2. They store the state for the context API (for example: usinguse_shared_state_provider).
  3. They store the current and previous versions of the VNode that was rendered, so they can bediffed to generate the set of mutations needed to re-render it.

The Initial Render

The root scope is created and rebuilt:

  1. The root component is run
  2. The root component returns a VNode
  3. Mutations for this VNode are created and added to the mutation list (this may involve creating new child components)
  4. The VNode is stored in the root's Scope.

After the root's Scope is built, all generated mutations are sent to the renderer, which applies them to the DOM.

After the initial render, the root Scope looks like this:

Waiting for Events

The Virtual DOM will only ever re-render a Scope if it is marked as dirty. Each hook is responsible for marking the Scope as dirty if the state has changed. Hooks can mark a scope as dirty by sending a message to the Virtual Dom's channel. You can see the implementations for the hooks dioxus includes by default on how this is done. Calling needs_update() on a hook will also cause it to mark its scope as dirty.

There are generally two ways a scope is marked as dirty:

  1. The renderer triggers an event: An event listener on this event may be called, which may mark acomponent as dirty, if processing the event resulted in any generated any mutations.
  2. The renderer callswait_for_work:This polls dioxus internal future queue. One of these futures may mark a component as dirty.

Once at least one Scope is marked as dirty, the renderer can call render_with_deadline to diff the dirty scopes.

Diffing Scopes

When a user clicks the "up high" button, the root Scope will be marked as dirty by the use_state hook. The desktop renderer will then call render_with_deadline, which will diff the root Scope.

To start the diffing process, the component function is run. After the root component is run it, the root Scope will look like this:

Next, the Virtual DOM will compare the new VNode with the previous VNode and only update the parts of the tree that have changed. Because of this approach, when a component is re-rendered only the parts of the tree that have changed will be updated in the DOM by the renderer.

The diffing algorithm goes through the list of dynamic attributes and nodes and compares them to the previous VNode. If the attribute or node has changed, a mutation that describes the change is added to the mutation list.

Here is what the diffing algorithm looks like for the root Scope (red lines indicate that a mutation was generated, and green lines indicate that no mutation was generated)

Conclusion

This is only a brief overview of how the Virtual Dom works. There are several aspects not yet covered in this guide including:

If you need more information about the Virtual Dom, you can read the code of the core crate or reach out to us on Discord.

+

Avoid Interior Mutability in Props

While it is technically acceptable to have a Mutex or a RwLock in the props, they will be difficult to use.

Suppose you have a struct User containing the field username: String. If you pass a Mutex<User> prop to a UserComponent component, that component may wish to pass the username as a &str prop to a child component. However, it cannot pass that borrowed field down, since it only would live as long as the Mutex's lock, which belongs to the UserComponent function. Therefore, the component will be forced to clone the username field.

Avoid Updating State During Render

Every time you update the state, Dioxus needs to re-render the component – this is inefficient! Consider refactoring your code to avoid this.

Also, if you unconditionally update the state during render, it will be re-rendered in an infinite loop.

+

Conclusion

That should be it! You should have nearly all the knowledge required on how to implement your renderer. We're super interested in seeing Dioxus apps brought to custom desktop renderers, mobile renderers, video game UI, and even augmented reality! If you're interested in contributing to any of these projects, don't be afraid to reach out or join the community.

+

This approach to error handling is best in apps that have "well defined" error states. Consider using a crate like thiserror or anyhow to simplify the generation of the error types.

This pattern is widely popular in many contexts and is particularly helpful whenever your code generates a non-recoverable error. You can gracefully capture these "global" error states without panicking or mucking up state.

+ + + + + + + + + + + + + + + + + +

Examples

There's a lot of these, so if you're having trouble implementing something, or you just want to see cool thingsthat you can do with Dioxus, make sure to give these a look!

Each of the examples in the main repository also has a permalink attached, in case the main one doesn't work.However, permalinks lead to an older "archived" version, so if you're reading this a long time in the future in a galaxy far, far away...The examples in the permalinks might not work.

+ + + + + + diff --git a/learn/0.4/cookbook/index.html b/learn/0.4/cookbook/index.html index eff26f621..9b52012ad 100644 --- a/learn/0.4/cookbook/index.html +++ b/learn/0.4/cookbook/index.html @@ -133,7 +133,7 @@ -

Cookbook

The cookbook contains common recipes for different patterns within Dioxus.

There are a few different sections in the cookbook:

  • Anti-patterns talks about what ingredients to avoid when developing your application
  • Error Handling discusses best around about error handling in Dioxus
  • Custom Renderer walks through the process of building a custom renderer for Dioxus
  • State discusses patterns around managing local, global, and external state in Dioxus
  • Integrations contains walkthroughs about integrating with external libraries
+

Cookbook

The cookbook contains common recipes for different patterns within Dioxus.

There are a few different sections in the cookbook:

  • Publishing will teach you how to present your app in a variety of delicious forms.
  • Explore the Anti-patterns section to discover what ingredients to avoid when preparing your application.
  • Within Error Handling, we'll master the fine art of managing spoiled ingredients in Dioxus.
  • Take a culinary journey through State management, where we'll explore the world of handling local, global, and external state in Dioxus.
  • Integrations will guide you how to seamlessly blend external libraries into your Dioxus culinary creations.
  • Testing explains how to examine the unique flavor of Dioxus-specific features, like components.
  • Examples is a curated list of delightful recipes that demonstrate the various ways of using Dioxus ingredients.
  • Tailwind reveals the secrets of combining your Tailwind and Dioxus ingredients into a complete meal. You will also learn about using other NPM ingredients (packages) with Dioxus.
  • In the Custom Renderer section, we embark on a cooking adventure, inventing new ways to cook with Dioxus!
+

This section of the guide provides getting started guides for common tools used with Dioxus.

+

Internationalization

If you application supports multiple languages, the Dioxus-std crate contains helpers to make working with translations in your application easier.

A full example is available here

+

Viewing Logs

You can view the emitted logs in Xcode.

For more information, visit oslog.

+

DESKTOP: Creating an Installer

Dioxus desktop app uses your operating system's WebView library, so it's portable to be distributed for other platforms.

In this section, we'll cover how to bundle your app for macOS, Windows, and Linux.

Install dioxus CLI

The first thing we'll do is install the dioxus-cli. This extension to cargo will make it very easy to package our app for the various platforms.

To install, simply run

cargo install dioxus-cli --locked

Building

To bundle your application you can simply run dx bundle --release to produce a final app with all the optimizations and assets builtin.

Once you've ran dx bundle --release, your app should be accessible in

dist/bundle/.

For example, a macOS app would look like this:

Published App

Nice! And it's only 4.8 Mb – extremely lean!! Because Dioxus leverages your platform's native WebView, Dioxus apps are extremely memory efficient and won't waste your battery.

Note: not all CSS works the same on all platforms. Make sure to view your app's CSS on each platform – or web browser (Firefox, Chrome, Safari) before publishing.

+ +

Making Reactive State External

If you have some reactive state (state that is rendered), that you want to modify from another thread, you can use the use_rw hook in the dioxus-std crate.

The use_rw hook works like the use_ref hook, but it is Send + Sync which makes it possible to move the hook into another thread.

+
+ + +

Choosing a web renderer

Dioxus has three different renderers that target the web:

  • dioxus-web allows you to render your application to HTML with WebAssembly on the client
  • dioxus-liveview allows you to run your application on the server and render it to HTML on the client with a websocket
  • dioxus-fullstack allows you to initially render static HTML on the server and then update that HTML from the client with WebAssembly

Each approach has its tradeoffs:

Dioxus Liveview

  • Liveview rendering communicates with the server over a WebSocket connection. It essentially moves all of the work that Client-side rendering does to the server.

  • This makes it easy to communicate with the server, but more difficult to communicate with the client/browser APIS.

  • Each interaction also requires a message to be sent to the server and back which can cause issues with latency.

  • Because Liveview uses a websocket to render, the page will be blank until the WebSocket connection has been established and the first renderer has been sent form the websocket. Just like with client side rendering, this can make the page less SEO-friendly.

  • Because the page is rendered on the server and the page is sent to the client piece by piece, you never need to send the entire application to the client. The initial load time can be faster than client-side rendering with large applications because Liveview only needs to send a constant small websocket script regardless of the size of the application.

Liveview is a good fit for applications that already need to communicate with the server frequently (like real time collaborative apps), but don't need to communicate with as many client/browser APIs

Dioxus Web

  • With Client side rendering, you send your application to the client, and then the client generates all of the HTML of the page dynamically.

  • This means that the page will be blank until the JavaScript bundle has loaded and the application has initialized. This can result in slower first render times and poor SEO performance.

SEO stands for Search Engine Optimization. It refers to the practice of making your website more likely to appear in search engine results. Search engines like Google and Bing use web crawlers to index the content of websites. Most of these crawlers are not able to run JavaScript, so they will not be able to index the content of your page if it is rendered client-side.

  • Client-side rendered applications need to use weakly typed requests to communicate with the server

Client-side rendering is a good starting point for most applications. It is well supported and makes it easy to communicate with the client/browser APIs

Dioxus Fullstack

Fullstack rendering happens in two parts:

  1. The page is rendered on the server. This can include fetching any data you need to render the page.
  2. The page is hydrated on the client. (Hydration is just taking the page from the server and adding all of the event listeners Dioxus needs on the client). Any updates to the page happen on the client after this point.

Because the page is initially rendered on the server, the page will be fully rendered when it is sent to the client. This results in a faster first render time and makes the page more SEO-friendly.

  • Fast initial render
  • Works well with SEO
  • Type safe easy communication with the server
  • Access to the client/browser APIs
  • Fast interactivity

Finally, we can use server functions to communicate with the server in a type-safe way.

This approach uses both the dioxus-web and dioxus-ssr crates. To integrate those two packages and axum, warp, or salvo, Dioxus provides the dioxus-fullstack crate.

There can be more complexity with fullstack applications because your code runs in two different places. Dioxus tries to mitigate this with server functions and other helpers.

+
  1. Change some code within a rsx or render macro
  2. Save and watch the style change without recompiling

Limitations

  1. The interpreter can only use expressions that existed on the last full recompile. If you introduce a new variable or expression to the rsx call, it will require a full recompile to capture the expression.
  2. Components, Iterators, and some attributes can contain arbitrary rust code and will trigger a full recompile when changed.
+
  1. Change some code within a rsx or render macro
  2. Save and watch the style change without recompiling

Limitations

  1. The interpreter can only use expressions that existed on the last full recompile. If you introduce a new variable or expression to the rsx call, it will require a full recompile to capture the expression.
  2. Components, Iterators, and some attributes can contain arbitrary rust code and will trigger a full recompile when changed.
+

Getting Started

This section will help you set up your Dioxus project!

Prerequisites

An Editor

Dioxus integrates very well with the Rust-Analyzer LSP plugin which will provide appropriate syntax highlighting, code navigation, folding, and more.

Rust

Head over to https://rust-lang.org and install the Rust compiler.

We strongly recommend going through the official Rust book completely. However, we hope that a Dioxus app can serve as a great first Rust project. With Dioxus, you'll learn about:

  • Error handling
  • Structs, Functions, Enums
  • Closures
  • Macros

We've put a lot of care into making Dioxus syntax familiar and easy to understand, so you won't need deep knowledge of async, lifetimes, or smart pointers until you start building complex Dioxus apps.

Setup Guides

Dioxus supports multiple platforms. Choose the platform you want to target below to get platform-specific setup instructions:

More information on any platform you choose is available in the section of the same name in the Reference

+
  1. Change some code within a rsx or render macro
  2. Save and watch the style change without recompiling

Limitations

  1. The interpreter can only use expressions that existed on the last full recompile. If you introduce a new variable or expression to the rsx call, it will require a full recompile to capture the expression.
  2. Components, Iterators, and some attributes can contain arbitrary rust code and will trigger a full recompile when changed.
+

android_demo

More information is available in the Android docs:

+
  1. Change some code within a rsx or render macro
  2. Save and watch the style change without recompiling

Limitations

  1. The interpreter can only use expressions that existed on the last full recompile. If you introduce a new variable or expression to the rsx call, it will require a full recompile to capture the expression.
  2. Components, Iterators, and some attributes can contain arbitrary rust code and will trigger a full recompile when changed.
+
  1. Change some code within a rsx or render macro
  2. Open your localhost in a browser
  3. Save and watch the style change without recompiling

Limitations

  1. The interpreter can only use expressions that existed on the last full recompile. If you introduce a new variable or expression to the rsx call, it will require a full recompile to capture the expression.
  2. Components, Iterators, and some attributes can contain arbitrary rust code and will trigger a full recompile when changed.
+
Loading items
Hover over a story to preview it here
+ + + +
hello hackernews ()
0 points
by Author
09/20/23 7:41 PM
0 comments
+

High-Five counter: 0

Dioxus is heavily inspired by React. If you know React, getting started with Dioxus will be a breeze.

This guide assumes you already know some Rust! If not, we recommend reading the book to learn Rust first.

Features

Multiplatform

Dioxus is a portable toolkit, meaning the Core implementation can run anywhere with no platform-dependent linking. Unlike many other Rust frontend toolkits, Dioxus is not intrinsically linked to WebSys. In fact, every element and event listener can be swapped out at compile time. By default, Dioxus ships with the html feature enabled, but this can be disabled depending on your target renderer.

Right now, we have several 1st-party renderers:

Stability

Dioxus has not reached a stable release yet.

Web: Since the web is a fairly mature platform, we expect there to be very little API churn for web-based features.

Desktop: APIs will likely be in flux as we figure out better patterns than our ElectronJS counterpart.

SSR: We don't expect the SSR API to change drastically in the future.

+ +

0.3 Migration Guide

This guide will outline the API changes between the 0.3 and 0.4 releases. The two major breaking changes in this release are how hot reloading works on desktop platforms and how the router works:

+

You can read more about programmatic navigation in the Router Book.

New features

In addition to these changes, there have been many new features added to the router:

+
How to not be seen
+

Dioxus Labs An Open Source project dedicated to making Rust UI wonderful.

Dioxus Labs An Open Source project dedicated to making Rust UI wonderful.

At this point, it might seem like components are nothing more than functions. However, as you learn more about the features of Dioxus, you'll see that they are actually more powerful!

+ +

Integrating with Wry

In cases where you need more low level control over your window, you can use wry APIs exposed through the Desktop Config and the use_window hook

+

The key Attribute

Every time you re-render your list, Dioxus needs to keep track of which items go where to determine what updates need to be made to the UI.

For example, suppose the CommentComponent had some state – e.g. a field where the user typed in a reply. If the order of comments suddenly changes, Dioxus needs to correctly associate that state with the same comment – otherwise, the user will end up replying to a different comment!

To help Dioxus keep track of list items, we need to associate each item with a unique key. In the example above, we dynamically generated the unique key. In real applications, it's more likely that the key will come from e.g. a database ID. It doesn't matter where you get the key from, as long as it meets the requirements:

You might be tempted to use an item's index in the list as its key. That’s what Dioxus will use if you don’t specify a key at all. This is only acceptable if you can guarantee that the list is constant – i.e., no re-ordering, additions, or deletions.

Note that if you pass the key to a component you've made, it won't receive the key as a prop. It’s only used as a hint by Dioxus itself. If your component needs an ID, you have to pass it as a separate prop.

+

Note: just like any other attribute, you can name the handlers anything you want! Though they must start with on, for the prop to be automatically turned into an EventHandler at the call site.

You can also put custom data in the event, rather than e.g. MouseData

+

Authentication

You can use extractors to integrate auth with your Fullstack application.

You can create a custom extractors that extracts the auth session from the request. From that auth session, you can check if the user has the required privileges before returning the private data.

A full auth example with the complete implementation is available in the fullstack examples.

+ +

Fullstack development

Dioxus Fullstack contains helpers for:

  • Incremental, static, and server side rendering
  • Hydrating your application on the Client
  • Communicating between a server and a client

This guide will teach you everything you need to know about how to use the utilities in Dioxus fullstack to create amazing fullstack applications.

In addition to this guide, you can find more examples of full-stack apps and information about how to integrate with other frameworks and desktop renderers in the dioxus-fullstack examples directory.

+ + +

Notice the ? after use_server_future. This is what tells Dioxus fullstack to wait for the future to resolve before continuing rendering. If you want to not wait for a specific future, you can just remove the ? and deal with the Option manually.

Now when you load the page, you should see server data is Ok("Hello from the server!"). No need to wait for the WASM to load or wait for the request to finish!

+

Current list: []

The return values of use_state and use_ref (UseState andUseRef, respectively) are insome ways similar to Cell andRefCell – they provide interiormutability. However, these Dioxus wrappers also ensure that the component gets re-renderedwhenever you change the state.

Additional Resources

+

Dioxus Reference

This Reference contains more detailed explanations for all concepts covered in the guide and more.

Rendering

  • RSX: Rsx is a HTML-like macro that allows you to declare UI
  • Components: Components are the building blocks of UI in Dioxus
  • Props: Props allow you pass information to Components
  • Event Listeners: Event listeners let you respond to user input
  • User Input: How to handle User input in Dioxus
  • Dynamic Rendering: How to dynamically render data in Dioxus

State

  • Hooks: Hooks allow you to create components state
  • Context: Context allows you to create state in a parent and consume it in children
  • Routing: The router helps you manage the URL state
  • UseFuture: Use future allows you to create an async task and monitor it's state
  • UseCoroutine: Use coroutine helps you manage external state
  • Spawn: Spawn creates an async task

Platforms

  • Desktop: Overview of desktop specific APIS
  • Web: Overview of web specific APIS
  • SSR: Overview of the SSR renderer
  • Liveview: Overview of liveview specific APIS
  • Fullstack: Overview of Fullstack specific APIS
    • Server Functions: Server functions make it easy to communicate between your server and client
    • Extractors: Extractors allow you to get extra information out of the headers of a request
    • Middleware: Middleware allows you to wrap a server function request or response
    • Authentication: An overview of how to handle authentication with server functions
    • Routing: An overview of how to work with the router in the fullstack renderer
+ +

More reading

This page is just a very brief overview of the router. For more information, check out the router book or some of the router examples.

+
true
+ +

Multithreaded Support

The Dioxus VirtualDom, sadly, is not currently Send. Internally, we use quite a bit of interior mutability which is not thread-safe.When working with web frameworks that require Send, it is possible to render a VirtualDom immediately to a String – but you cannot hold the VirtualDom across an await point. For retained-state SSR (essentially LiveView), you'll need to spawn a VirtualDom on its own thread and communicate with it via channels or create a pool of VirtualDoms.You might notice that you cannot hold the VirtualDom across an await point. Because Dioxus is currently not ThreadSafe, it must remain on the thread it started. We are working on loosening this requirement.

+ + + +

If you are targeting web, but don't plan on targeting any other Dioxus renderer you can also use the generated wrappers in the web-sys and gloo crates.

+

That's it! If you head to /blog/1 you should see our sample post.

Conclusion

In this chapter, we utilized Dioxus Router's Link, and Route Parameterfunctionality to build the blog portion of our application. In the next chapter,we will go over how navigation targets (like the one we passed to our links)work.

+

Now when you go to a route that doesn't exist, you should see the page not foundtext.

Conclusion

In this chapter, we learned how to create a route and tell Dioxus Router whatcomponent to render when the URL path is /. We also created a 404 page tohandle when a route doesn't exist. Next, we'll create the blog portion of oursite. We will utilize nested routes and URL parameters.

+ +

Overview

In this guide, you'll learn to effectively use Dioxus Router whether you'rebuilding a small todo app or the next FAANG company. We will create a smallwebsite with a blog, homepage, and more!

To follow along with the router example, you'll need a working Dioxus app.Check out the Dioxus book to get started.

Make sure to add Dioxus Router as a dependancy, as explained in theintroduction.

You'll learn how to

  • Create routes and render "pages".
  • Utilize nested routes, create a navigation bar, and render content for aset of routes.
  • Parse URL parameters to dynamically display content.
  • Redirect visitors to different routes.

Disclaimer

The example will only display the features of Dioxus Router. It will notinclude any actual functionality. To keep things simple we will only be usinga single file, this is not the recommended way of doing things with a realapplication.

You can find the complete application in the full code chapter.

+ +

That's it! Now your users will be redirected to the blog.

Conclusion

Well done! You've completed the Dioxus Router guide. You've built a smallapplication and learned about the many things you can do with Dioxus Router.To continue your journey, you attempt a challenge listed below, look at the router examples, orcan check out the API reference.

Challenges

+

This book is intended to get you up to speed with Dioxus Router. It is splitinto two sections:

  1. The reference section explains individual features in depth. You can read it from start to finish, or you can read individual chapters in whatever order you want.
  2. If you prefer a learning-by-doing approach, you can check out the example project. It guides you through creating a dioxus app, setting up the router, and using some of its functionality.

Please note that this is not the only documentation for the Dioxus Router. Youcan also check out the API Docs.

+

As you might know, browsers usually disable the back and forward buttons ifthere is no history to navigate to. The router's history buttons try to do thattoo, but depending on the [history provider] that might not be possible.

Importantly, neither [WebHistory] supports that feature.This is due to limitations of the browser History API.

However, in both cases, the router will just ignore button presses, if there isno history to navigate to.

Also, when using [WebHistory], the history buttons mightnavigate a user to a history entry outside your app.

+ + + +

The target in the example above is similar to the href of a regular anchorelement. However, it tells the router more about what kind of navigation itshould perform. It accepts something that can be converted into a[NavigationTarget]:

The [Link] accepts several props that modify its behavior. See the API docsfor more details.

+

You might have noticed that, like [Link], the [Navigator]s push andreplace functions take a [NavigationTarget]. This means we can use either[Internal], or [External] targets.

External Navigation Targets

Unlike a [Link], the [Navigator] cannot rely on the browser (or webview) tohandle navigation to external targets via a generated anchor element.

This means, that under certain conditions, navigation to external targets canfail.

+ + + +