Skip to content

Commit b392343

Browse files
committed
chore: add examples
1 parent 076250c commit b392343

15 files changed

+624
-12
lines changed

Cargo.toml

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,27 @@
1+
[workspace]
2+
resolver = "2"
3+
members = [
4+
"examples/*",
5+
]
6+
7+
[workspace.dependencies]
8+
viz = "0.8.0"
9+
futures = "0.3"
10+
http = "1.0.0"
11+
http-body-util = "0.1.0"
12+
hyper = "1.1.0"
13+
serde = { version = "1", features = ["derive"] }
14+
serde_json = "1"
15+
tokio = { version = "1", default-features = false }
16+
parking_lot = "0.12.1"
17+
18+
leptos_viz = { path = "." }
19+
leptos = { git = "https://github.com/leptos-rs/leptos.git", rev = "1eaf886" }
20+
leptos_meta = { git = "https://github.com/leptos-rs/leptos.git", rev = "1eaf886" }
21+
leptos_router = { git = "https://github.com/leptos-rs/leptos.git", rev = "1eaf886" }
22+
leptos_reactive = { git = "https://github.com/leptos-rs/leptos.git", rev = "1eaf886" }
23+
leptos_integration_utils = { git = "https://github.com/leptos-rs/leptos.git", rev = "1eaf886" }
24+
125
[package]
226
name = "leptos_viz"
327
version = "0.6.0"
@@ -8,18 +32,21 @@ repository = "https://github.com/leptos-rs/leptos"
832
description = "Viz integrations for the Leptos web framework."
933

1034
[dependencies]
11-
viz = "0.8.0"
12-
futures = "0.3"
13-
http = "1.0.0"
14-
http-body-util = "0.1.0"
15-
hyper = "1.1.0"
16-
leptos = { git = "https://github.com/leptos-rs/leptos.git", rev = "1eaf886", features = ["ssr"] }
17-
leptos_meta = { git = "https://github.com/leptos-rs/leptos.git", rev = "1eaf886", features = ["ssr"] }
18-
leptos_router = { git = "https://github.com/leptos-rs/leptos.git", rev = "1eaf886", features = ["ssr"] }
19-
leptos_integration_utils = { git = "https://github.com/leptos-rs/leptos.git", rev = "1eaf886" }
20-
serde_json = "1"
21-
tokio = { version = "1", features = ["full"] }
22-
parking_lot = "0.12.1"
35+
viz.workspace = true
36+
futures.workspace = true
37+
http.workspace = true
38+
http-body-util.workspace = true
39+
hyper.workspace = true
40+
leptos = { workspace = true, features = ["ssr"] }
41+
leptos_meta = { workspace = true, features = ["ssr"] }
42+
leptos_router = { workspace = true, features = ["ssr"] }
43+
leptos_integration_utils.workspace = true
44+
serde_json.workspace = true
45+
tokio.workspace = true
46+
parking_lot.workspace = true
47+
48+
[dev-dependencies]
49+
tokio = { workspace = true, features = ["full"] }
2350

2451
[features]
2552
nonce = ["leptos/nonce"]
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
[package]
2+
name = "todo_app_sqlite_viz"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[lib]
7+
crate-type = ["cdylib", "rlib"]
8+
9+
[dependencies]
10+
console_log = "1.0.0"
11+
console_error_panic_hook = "0.1.7"
12+
cfg-if = "1.0.0"
13+
log = "0.4.17"
14+
simple_logger = "4.0.0"
15+
sqlx = { version = "0.6.2", features = [
16+
"runtime-tokio-rustls",
17+
"sqlite",
18+
], optional = true }
19+
thiserror = "1.0.38"
20+
wasm-bindgen = "0.2"
21+
22+
serde.workspace = true
23+
viz = { workspace = true, optional = true }
24+
tokio = { workspace = true, features = ["full"], optional = true }
25+
http.workspace = true
26+
futures.workspace = true
27+
leptos.workspace = true
28+
leptos_viz = { workspace = true, optional = true }
29+
leptos_meta = { workspace = true, features = ["nightly"] }
30+
leptos_router = { workspace = true, features = ["nightly"] }
31+
leptos_reactive = { workspace = true, features = ["nightly"] }
32+
33+
[features]
34+
csr = ["leptos/csr", "leptos_meta/csr", "leptos_router/csr"]
35+
hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]
36+
ssr = [
37+
"dep:viz",
38+
"dep:tokio",
39+
"dep:sqlx",
40+
"leptos/ssr",
41+
"leptos_meta/ssr",
42+
"leptos_router/ssr",
43+
"dep:leptos_viz",
44+
]
45+
46+
[package.metadata.cargo-all-features]
47+
denylist = ["viz", "tokio", "sqlx", "leptos_viz"]
48+
skip_feature_sets = [["csr", "ssr"], ["csr", "hydrate"], ["ssr", "hydrate"]]
49+
50+
[package.metadata.leptos]
51+
# The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name
52+
output-name = "todo_app_sqlite_viz"
53+
# The site root folder is where cargo-leptos generate all output. WARNING: all content of this folder will be erased on a rebuild. Use it in your server setup.
54+
site-root = "target/site"
55+
# The site-root relative folder where all compiled output (JS, WASM and CSS) is written
56+
# Defaults to pkg
57+
site-pkg-dir = "pkg"
58+
# [Optional] The source CSS file. If it ends with .sass or .scss then it will be compiled by dart-sass into CSS. The CSS is optimized by Lightning CSS before being written to <site-root>/<site-pkg>/app.css
59+
style-file = "./style.css"
60+
# [Optional] Files in the asset-dir will be copied to the site-root directory
61+
assets-dir = "public"
62+
# The IP and port (ex: 127.0.0.1:3000) where the server serves the content. Use it in your server setup.
63+
site-addr = "127.0.0.1:3000"
64+
# The port to use for automatic reload monitoring
65+
reload-port = 3001
66+
# [Optional] Command to use when running end2end tests. It will run in the end2end dir.
67+
end2end-cmd = "npx playwright test"
68+
# The browserlist query used for optimizing the CSS.
69+
browserquery = "defaults"
70+
# Set by cargo-leptos watch when building with tha tool. Controls whether autoreload JS will be included in the head
71+
watch = false
72+
# The environment Leptos will run in, usually either "DEV" or "PROD"
73+
env = "DEV"
74+
# The features to use when compiling the bin target
75+
#
76+
# Optional. Can be over-ridden with the command line parameter --bin-features
77+
bin-features = ["ssr"]
78+
79+
# If the --no-default-features flag should be used when compiling the bin target
80+
#
81+
# Optional. Defaults to false.
82+
bin-default-features = false
83+
84+
# The features to use when compiling the lib target
85+
#
86+
# Optional. Can be over-ridden with the command line parameter --lib-features
87+
lib-features = ["hydrate"]
88+
89+
# If the --no-default-features flag should be used when compiling the lib target
90+
#
91+
# Optional. Defaults to false.
92+
lib-default-features = false

examples/todo_app_sqlite_viz/LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2022 Greg Johnston
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Leptos Todo App Sqlite with Viz
2+
3+
This example creates a basic todo app with a Viz backend that uses Leptos' server functions to call sqlx from the client and seamlessly run it on the server.
4+
5+
## Getting Started
6+
7+
See the [Examples README](../README.md) for setup and run instructions.
8+
9+
## Rendering
10+
11+
See the [SSR Notes](../SSR_NOTES.md) for more information about Server Side Rendering.
12+
13+
## Quick Start
14+
15+
Run `cargo leptos watch` to run this example.

examples/todo_app_sqlite_viz/Todos.db

16 KB
Binary file not shown.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
CREATE TABLE IF NOT EXISTS todos
3+
(
4+
id INTEGER NOT NULL PRIMARY KEY,
5+
title VARCHAR,
6+
completed BOOLEAN
7+
);
Binary file not shown.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[toolchain]
2+
channel = "nightly"
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
use crate::errors::TodoAppError;
2+
use cfg_if::cfg_if;
3+
use leptos::{Errors, *};
4+
#[cfg(feature = "ssr")]
5+
use leptos_viz::ResponseOptions;
6+
7+
// A basic function to display errors served by the error boundaries. Feel free to do more complicated things
8+
// here than just displaying them
9+
#[component]
10+
pub fn ErrorTemplate(
11+
#[prop(optional)] outside_errors: Option<Errors>,
12+
#[prop(optional)] errors: Option<RwSignal<Errors>>,
13+
) -> impl IntoView {
14+
let errors = match outside_errors {
15+
Some(e) => create_rw_signal(e),
16+
None => match errors {
17+
Some(e) => e,
18+
None => panic!("No Errors found and we expected errors!"),
19+
},
20+
};
21+
22+
// Get Errors from Signal
23+
// Downcast lets us take a type that implements `std::error::Error`
24+
let errors: Vec<TodoAppError> = errors
25+
.get()
26+
.into_iter()
27+
.filter_map(|(_k, v)| v.downcast_ref::<TodoAppError>().cloned())
28+
.collect();
29+
30+
// Only the response code for the first error is actually sent from the server
31+
// this may be customized by the specific application
32+
cfg_if! {
33+
if #[cfg(feature="ssr")]{
34+
let response = use_context::<ResponseOptions>();
35+
if let Some(response) = response{
36+
response.set_status(errors[0].status_code());
37+
}
38+
}
39+
}
40+
41+
view! {
42+
<h1>"Errors"</h1>
43+
<For
44+
// a function that returns the items we're iterating over; a signal is fine
45+
each= move || {errors.clone().into_iter().enumerate()}
46+
// a unique key for each item as a reference
47+
key=|(index, _error)| *index
48+
// renders each item to a view
49+
children= move |error| {
50+
let error_string = error.1.to_string();
51+
let error_code= error.1.status_code();
52+
view! {
53+
54+
<h2>{error_code.to_string()}</h2>
55+
<p>"Error: " {error_string}</p>
56+
}
57+
}
58+
/>
59+
}
60+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
use http::status::StatusCode;
2+
use thiserror::Error;
3+
4+
#[derive(Debug, Clone, Error)]
5+
pub enum TodoAppError {
6+
#[error("Not Found")]
7+
NotFound,
8+
#[error("Internal Server Error")]
9+
InternalServerError,
10+
}
11+
12+
impl TodoAppError {
13+
pub fn status_code(&self) -> StatusCode {
14+
match self {
15+
TodoAppError::NotFound => StatusCode::NOT_FOUND,
16+
TodoAppError::InternalServerError => StatusCode::INTERNAL_SERVER_ERROR,
17+
}
18+
}
19+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
use cfg_if::cfg_if;
2+
3+
cfg_if! {
4+
if #[cfg(feature = "ssr")] {
5+
use crate::{
6+
error_template::ErrorTemplate,
7+
errors::TodoAppError,
8+
};
9+
use http::Uri;
10+
use std::sync::Arc;
11+
use leptos::{view, Errors, LeptosOptions};
12+
use viz::{
13+
handlers::serve, header::HeaderMap, types::RouteInfo, Body, Error, Handler,
14+
Request, RequestExt, Response, ResponseExt, Result,
15+
};
16+
17+
pub async fn file_and_error_handler(req: Request<Body>) -> Result<Response> {
18+
let uri = req.uri().clone();
19+
let headers = req.headers().clone();
20+
let route_info = req.route_info().clone();
21+
let options = req.state::<LeptosOptions>().ok_or(
22+
Error::Responder(Response::text("missing state type LeptosOptions")),
23+
)?;
24+
let root = &options.site_root;
25+
let resp = get_static_file(uri, root, headers, route_info).await?;
26+
let status = resp.status();
27+
28+
if status.is_success() || status.is_redirection() {
29+
Ok(resp)
30+
} else {
31+
let mut errors = Errors::default();
32+
errors.insert_with_default_key(TodoAppError::NotFound);
33+
let handler = leptos_viz::render_app_to_stream(
34+
options.to_owned(),
35+
move || view! {<ErrorTemplate outside_errors=errors.clone()/>},
36+
);
37+
handler(req).await
38+
}
39+
}
40+
41+
async fn get_static_file(
42+
uri: Uri,
43+
root: &str,
44+
headers: HeaderMap,
45+
route_info: Arc<RouteInfo>,
46+
) -> Result<Response> {
47+
let mut req = Request::builder()
48+
.uri(uri.clone())
49+
.extension(route_info)
50+
.body(Body::empty())
51+
.unwrap();
52+
*req.headers_mut() = headers;
53+
// This path is relative to the cargo root
54+
serve::Dir::new(root).call(req).await
55+
}
56+
57+
}
58+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
use cfg_if::cfg_if;
2+
pub mod error_template;
3+
pub mod errors;
4+
pub mod fallback;
5+
pub mod todo;
6+
7+
// Needs to be in lib.rs AFAIK because wasm-bindgen needs us to be compiling a lib. I may be wrong.
8+
cfg_if! {
9+
if #[cfg(feature = "hydrate")] {
10+
use leptos::*;
11+
use wasm_bindgen::prelude::wasm_bindgen;
12+
use crate::todo::*;
13+
14+
#[wasm_bindgen]
15+
pub fn hydrate() {
16+
_ = console_log::init_with_level(log::Level::Debug);
17+
console_error_panic_hook::set_once();
18+
19+
leptos::mount_to_body(|| {
20+
view! { <TodoApp/> }
21+
});
22+
}
23+
}
24+
}

0 commit comments

Comments
 (0)