spair
A framework for Single Page Application in Rust. Inspired by Simi, Mika and Yew, some parts of source are copied from them.
This project is in its early stage, breaking changes are expected.
Run examples
Prerequisites:
- Rust with
wasm32-unknown-unknowntarget. cargo install wasm-packcargo install basic-http-serveror use your favorite file-server
To build and serve (in an example folder):
wasm-pack build --dev --target web
basic-http-server // or your favorite file-server
Open your browser and visit the correct url. By default, basic-http-server serves at http://localhost:4000.
Documentation
Not yet. /examples/* is the best place to start now.
Sections below provide first looks into Spair.
Static-mode and update-mode
Spair works by iterating through every elements and attributes/properties in the current DOM, which is empty before the first render, creating new items or modifying existing items, it's the update-mode. But there are elements or attributes that will never change. You can tell Spair to just create them but ignore them when iterating over them later by turn on the static-mode.
| items | update-mode | static-mode | notes |
|---|---|---|---|
| attributes / properties | default | .static_attributes() |
call .static_attributes() after you are done with update-mode-attributes |
| elements | default, .nodes() |
.static_nodes() |
only apply to elements, not apply to texts/renderable-items |
| texts / renderable-items | .render(value) |
.r#static(value) |
not affected by mode introduced by .nodes() or .static_nodes() |
.nodes() and .static_nodes() can be switched back and forth as many times as you want.
element
// default to update-mode attributes
.value // will be checked and updated if changed
.class_if
.static_attributes // we are done with update-mode attributes!
.class // class="class-name" is added on creation, but ignored on subsequence render
// just add child-elements, default to update mode.
.p // create and update a <p>
.render // create and update a text
.r#static // a create-only text - not affected by update-mode (default).
.static_nodes
.div // a create-only <div> (because creating in static-mode)
.render // an updatable text - not affected by `.static_nodes()`
.r#static // a create-only text - because of `r#static`, not `static_nodes`
- Important note: when an element is creating in static mode, all its content will be ignored (not update) in future updates.
element
.static_nodes
.p
Example
Look in /examples for full examples
This is the render method of examples/counter:
Render and StaticRender traits
You can split your codes into small pieces by implement Render or StaticRender on your data types and pass the values to .render() or .r#static() respectively.
Render and StaticRender are implemented for primitives (i8, ..., u64, f32, f64, bool, usize, isize). They are simply converted to strings and rendered as text nodes.
Access to the component state.
When implementing Render, StaticRender or ListItem for your data types, you may want to access the state of your component:
Reconciliation? - No, you must use .match_if()
Spair does not do reconciliation, users must do it by themselves. When an expected element is not found, Spair create it, but if Spair found an element at the expected index, Spair just assume it is the expected element. Therefore, when you want to render different elements base on a condition, you must tell Spair to do that via .match_if().
The following code is extracted from examples/fetch/src/lib.rs:
element
.match_if
DON'T DO THIS, IT DOES NOT WORK
if some_condition else
Child components
Spair supports child components, but you do not have to use them if you can avoid them.
Example: examples/components
Notes
HTML's tags and attributes are implemented as methods in Spair. Names that are conflicted with Rust's keywords are implemented using raw identifers such as r#type, r#for...
There is an element named <span>, there is also an attribute named span. Spair implements methods for both elements and attributes on the spair::Element, so there is a conflict here. Spair implements .span() for element <span> and span_attr() for attribute span.
Common errors
Using Spair, you may encounter common mistakes listed in this section. They are really annoying. How these problems can be avoided?
static_attributes()
If you set an attribute in static-mode it will never be updated. It is easy to misplace an update-mode attribute under static-mode.
What's done?
- Non-keyed-list
- Keyed-list (behind
features=["keyed-list"]) - Support for
fetch- JSON:
features=["fetch-json"] - RON:
features=["fetch-ron"] - I believe it's ready to add other formats
- JSON:
- Basic support for routing
What's next?
(But don't expect soon)
- Using Spair for some apps to stabilize API
- Documentation
- Implement
#[derive(spair::Routes)] - Add support for child components
- Some benchmarks
- Proc macro to convert HTML-like or other short-clear syntax to Spair's Rust code.
- Using child components is inevitable in complex apps. Is it possible to reduce additional size causes by multi components?