a2a8cc93
—
Peter John 3 years ago
update readme
README.md
CHANGED
|
@@ -1,119 +1,53 @@
|
|
|
1
|
-
# tide-jsx
|
|
1
|
+
# tide-jsx [](https://github.com/pyrossh/tide-jsx/actions?query=workflow%3ATest) [](https://crates.io/crates/tide-jsx)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This crate allows to use jsx like templating engine (which is a slightly modified version of [render.rs](https://github.com/render-rs/render.rs)) as templates in your tide request handlers.
|
|
4
|
-
component tree, and call `render` on it:
|
|
5
4
|
|
|
6
|
-
```rust
|
|
7
|
-
use tide_jsx::{rsx, Render};
|
|
8
|
-
|
|
9
|
-
let tree = rsx! {
|
|
10
|
-
|
|
5
|
+
## Example
|
|
11
|
-
<h1>{"Hello!"}</h1>
|
|
12
|
-
<p>{"Hello world!"}</p>
|
|
13
|
-
</div>
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
assert_eq!(tree.render(), "<div><h1>Hello!</h1><p>Hello world!</p></div>");
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
Because this is so common, there's another macro called `html!` that calls `rsx!` to generate
|
|
20
|
-
a component tree, and then calls `render` on it. Most of the time, you'll find yourself using
|
|
21
|
-
the `rsx!` macro to compose arbitrary components, and only calling `html!` when you need a
|
|
22
|
-
String output, when sending a response or generating a Markdown file.
|
|
23
|
-
|
|
24
|
-
In Render, attributes and plain strings are escaped using the `render::html_escaping` module. In order to
|
|
25
|
-
use un-escaped values so you can dangerously insert raw HTML, use the `raw!` macro around your
|
|
26
|
-
string:
|
|
27
6
|
|
|
28
7
|
```rust
|
|
8
|
+
use tide::http::mime;
|
|
9
|
+
use tide::utils::After;
|
|
10
|
+
use tide::{log, Request, Response};
|
|
29
|
-
use tide_jsx::
|
|
11
|
+
use tide_jsx::html::HTML5Doctype;
|
|
30
|
-
|
|
31
|
-
let tree = html! {
|
|
32
|
-
<div>
|
|
33
|
-
<p>{"<Hello />"}</p>
|
|
34
|
-
<p>{raw!("<Hello />")}</p>
|
|
35
|
-
</div>
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
assert_eq!(tree, "<div><p><Hello /></p><p><Hello /></p></div>");
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### Custom components
|
|
42
|
-
|
|
43
|
-
Render's greatest ability is to provide type-safety along with custom renderable components.
|
|
44
|
-
Introducing new components is as easy as defining a function that returns a `Render` value.
|
|
45
|
-
|
|
46
|
-
In order to build up components from other components or HTML nodes, you can use the `rsx!`
|
|
47
|
-
macro, which generates a `Render` component tree:
|
|
48
|
-
|
|
49
|
-
```rust
|
|
50
|
-
use tide_jsx::{component, rsx,
|
|
12
|
+
use tide_jsx::{component, rsx, view};
|
|
51
13
|
|
|
52
14
|
#[component]
|
|
53
15
|
fn Heading<'title>(title: &'title str) {
|
|
54
|
-
|
|
16
|
+
rsx! { <h1 class={"title"}>{title}</h1> }
|
|
55
17
|
}
|
|
56
18
|
|
|
19
|
+
async fn index(_req: Request<()>) -> tide::Result {
|
|
20
|
+
view! {
|
|
21
|
+
<>
|
|
57
|
-
|
|
22
|
+
<HTML5Doctype />
|
|
23
|
+
<html>
|
|
24
|
+
<head><title>{"Tide JSX"}</title></head>
|
|
25
|
+
<body>
|
|
26
|
+
<div>
|
|
58
|
-
|
|
27
|
+
<Heading title={"Hello world"} />
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
assert_eq!(rendered_html, r#"<h1 class="title">Hello world!</h1>"#);
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
If you pay close attention, you see that the function `Heading` is:
|
|
65
|
-
|
|
66
|
-
- declared with an uppercase. Underneath, it generates a struct with the same name, and
|
|
67
|
-
implements the `Render` trait on it.
|
|
68
|
-
- does not have a return type. This is because everything is written to a writer, for
|
|
69
|
-
performance reasons.
|
|
70
|
-
|
|
71
|
-
### Visibility & Component Libraries
|
|
72
|
-
|
|
73
|
-
Often you're going to want to store your components somewhere else in your
|
|
74
|
-
project tree other than the module you're working on (if not in a different
|
|
75
|
-
module entirely!). In these cases, the visibility applied top the function that
|
|
76
|
-
defines your component will flow down into all fields of that struct.
|
|
77
|
-
|
|
78
|
-
For example, if we add "pub" to the front of our Heading component above:
|
|
79
|
-
|
|
80
|
-
```rust
|
|
81
|
-
#[component]
|
|
82
|
-
pub fn Heading<'title>(title: &'title str) {
|
|
83
|
-
rsx! { <h1 class={"title"}>{title}</h1> }
|
|
84
|
-
}
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
...the struct that is generated would look something like...
|
|
88
|
-
|
|
89
|
-
```rust
|
|
90
|
-
pub struct Heading {
|
|
91
|
-
|
|
28
|
+
</div>
|
|
92
|
-
}
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
This is important to understand from a safety point of view when structuring
|
|
96
|
-
your libraries.
|
|
97
|
-
|
|
98
|
-
#### Full example
|
|
99
|
-
|
|
100
|
-
```rust
|
|
101
|
-
use render::html::HTML5Doctype;
|
|
102
|
-
use render::{component, rsx, html, Render};
|
|
103
|
-
|
|
104
|
-
#[component]
|
|
105
|
-
fn Page<'a, Children: Render>(title: &'a str, children: Children) {
|
|
106
|
-
rsx! {
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
pub fn some_page(user_name: &str) -> String {
|
|
112
|
-
html! {
|
|
113
|
-
<Page title={"Home"}>
|
|
114
|
-
{format!("Welcome, {}", user_name)}
|
|
115
|
-
|
|
29
|
+
</body>
|
|
30
|
+
</html>
|
|
31
|
+
</>
|
|
116
32
|
}
|
|
117
33
|
}
|
|
118
34
|
|
|
35
|
+
#[async_std::main]
|
|
36
|
+
async fn main() -> tide::Result<()> {
|
|
37
|
+
log::start();
|
|
38
|
+
let mut app = tide::new();
|
|
39
|
+
app.with(tide::log::LogMiddleware::new());
|
|
40
|
+
app.with(After(|mut res: Response| async {
|
|
41
|
+
if let Some(err) = res.error() {
|
|
42
|
+
let msg = format!("<h1>Error: {:?}</h1>", err);
|
|
43
|
+
res.set_status(err.status());
|
|
44
|
+
res.set_content_type(mime::HTML);
|
|
45
|
+
res.set_body(msg);
|
|
46
|
+
}
|
|
47
|
+
Ok(res)
|
|
48
|
+
}));
|
|
49
|
+
app.at("/").get(index);
|
|
50
|
+
app.listen("127.0.0.1:5000").await?;
|
|
51
|
+
Ok(())
|
|
52
|
+
}
|
|
119
53
|
```
|