diff --git a/Cargo.toml b/Cargo.toml index a8a25de90ac..d071706805c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,9 @@ members = [ "examples/password_strength", "examples/portals", "examples/router", - "examples/simple_ssr", + "examples/simple-ssr/yew-ssr-actix-web", + "examples/simple-ssr/yew-ssr-tide", + "examples/simple-ssr/yew-ssr-warp", "examples/timer", "examples/todomvc", "examples/two_apps", diff --git a/examples/simple-ssr/yew-ssr-actix-web/Cargo.toml b/examples/simple-ssr/yew-ssr-actix-web/Cargo.toml new file mode 100644 index 00000000000..b6cf6b57976 --- /dev/null +++ b/examples/simple-ssr/yew-ssr-actix-web/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "yew-ssr-actix-web" +version = "0.0.1" +edition = "2021" + +[dependencies] +tokio = { version = "1.17.0", features = ["full"] } +actix-web = "4.0.0-rc.1" +yew = { path = "../../../packages/yew", features = ["ssr"] } + +reqwest = { version = "0.11.9", features = ["json"] } +serde = { version = "1.0.136", features = ["derive"] } diff --git a/examples/simple-ssr/yew-ssr-actix-web/README.md b/examples/simple-ssr/yew-ssr-actix-web/README.md new file mode 100644 index 00000000000..9d01a61b856 --- /dev/null +++ b/examples/simple-ssr/yew-ssr-actix-web/README.md @@ -0,0 +1,6 @@ +# Yew Server-side Rendering with actix-web & reqwest + +This example demonstrates server-side rendering with actix-web & reqwest. + +Run `cargo run -p yew-ssr-actix-web` and navigate to http://localhost:8080/ to +view results. diff --git a/examples/simple-ssr/yew-ssr-actix-web/src/main.rs b/examples/simple-ssr/yew-ssr-actix-web/src/main.rs new file mode 100644 index 00000000000..4a4b0375f90 --- /dev/null +++ b/examples/simple-ssr/yew-ssr-actix-web/src/main.rs @@ -0,0 +1,141 @@ +use std::cell::RefCell; +use std::rc::Rc; + +use actix_web::{get, App as ActixApp, Error, HttpResponse, HttpServer}; +use tokio::task::LocalSet; +use tokio::task::{spawn_blocking, spawn_local}; + +use serde::{Deserialize, Serialize}; + +use yew::prelude::*; +use yew::suspense::{Suspension, SuspensionResult}; + +#[derive(Serialize, Deserialize, Clone)] +struct UserResponse { + login: String, + name: String, + blog: String, + location: String, +} + +async fn fetch_user() -> UserResponse { + // reqwest works for both non-wasm and wasm targets. + let resp = reqwest::Client::new() + .get("https://api.github.com/users/zzy") + .header("User-Agent", "request") + .send() + .await + .unwrap(); + println!("Status: {}", resp.status()); + + let user_resp = resp.json::().await.unwrap(); + + user_resp +} + +pub struct UserState { + susp: Suspension, + value: Rc>>, +} + +impl UserState { + fn new() -> Self { + let (susp, handle) = Suspension::new(); + let value: Rc>> = Rc::default(); + + { + let value = value.clone(); + // we use tokio spawn local here. + spawn_local(async move { + let user = fetch_user().await; + { + let mut value = value.borrow_mut(); + *value = Some(user); + } + + handle.resume(); + }); + } + + Self { susp, value } + } +} + +#[hook] +fn use_user() -> SuspensionResult { + let user_state = use_state(UserState::new); + + let result = match *user_state.value.borrow() { + Some(ref user) => Ok(user.clone()), + None => Err(user_state.susp.clone()), + }; + + result +} + +#[function_component] +fn Content() -> HtmlResult { + let user = use_user()?; + + Ok(html! { +
+
{"Login name: "}{ user.login }
+
{"User name: "}{ user.name }
+
{"Blog: "}{ user.blog }
+
{"Location: "}{ user.location }
+
+ }) +} + +#[function_component] +fn App() -> Html { + let fallback = html! {
{"Loading..."}
}; + + html! { + + + + } +} + +#[get("/")] +async fn render() -> Result { + let content = spawn_blocking(move || { + use tokio::runtime::Builder; + let set = LocalSet::new(); + + let rt = Builder::new_current_thread().enable_all().build().unwrap(); + + set.block_on(&rt, async { + let renderer = yew::ServerRenderer::::new(); + + renderer.render().await + }) + }) + .await + .expect("the thread has failed."); + + Ok(HttpResponse::Ok() + .content_type("text/html; charset=utf-8") + .body(format!( + r#" + + + yew-ssr with actix-web example + + +

yew-ssr with actix-web example

+ {} + + + "#, + content + ))) +} + +#[actix_web::main] // or #[tokio::main] +async fn main() -> std::io::Result<()> { + let server = HttpServer::new(|| ActixApp::new().service(render)); + println!("You can view the website at: http://localhost:8080/"); + server.bind(("127.0.0.1", 8080))?.run().await +} diff --git a/examples/simple-ssr/yew-ssr-tide/Cargo.toml b/examples/simple-ssr/yew-ssr-tide/Cargo.toml new file mode 100644 index 00000000000..54d5c64f780 --- /dev/null +++ b/examples/simple-ssr/yew-ssr-tide/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "yew-ssr-tide" +version = "0.0.1" +edition = "2021" + +[dependencies] +async-std = { version = "1.10.0", features = ["attributes"] } +tide = "0.17.0-beta.1" +yew = { path = "../../../packages/yew", features = ["ssr"] } + +surf = "2.3.2" +serde = { version = "1.0.136", features = ["derive"] } diff --git a/examples/simple-ssr/yew-ssr-tide/README.md b/examples/simple-ssr/yew-ssr-tide/README.md new file mode 100644 index 00000000000..41aef18e360 --- /dev/null +++ b/examples/simple-ssr/yew-ssr-tide/README.md @@ -0,0 +1,6 @@ +# Yew Server-side Rendering with tide & surf + +This example demonstrates server-side rendering with tide & surf. + +Run `cargo run -p yew-ssr-tide` and navigate to http://localhost:8080/ to +view results. diff --git a/examples/simple-ssr/yew-ssr-tide/src/main.rs b/examples/simple-ssr/yew-ssr-tide/src/main.rs new file mode 100644 index 00000000000..b9d094d3247 --- /dev/null +++ b/examples/simple-ssr/yew-ssr-tide/src/main.rs @@ -0,0 +1,136 @@ +use std::cell::RefCell; +use std::rc::Rc; + +use async_std::task; +use serde::{Deserialize, Serialize}; +use tide::{http::mime, Request, Response, StatusCode}; + +use yew::prelude::*; +use yew::suspense::{Suspension, SuspensionResult}; + +#[derive(Serialize, Deserialize, Clone)] +struct UserResponse { + login: String, + name: String, + blog: String, + location: String, +} + +async fn fetch_user() -> UserResponse { + // surf works for both non-wasm and wasm targets. + let mut resp = surf::get("https://api.github.com/users/zzy") + .header("User-Agent", "request") + .await + .unwrap(); + println!("Status: {:#?}", resp.status()); + + let user_resp: UserResponse = resp.body_json().await.unwrap(); + + user_resp +} + +pub struct UserState { + susp: Suspension, + value: Rc>>, +} + +impl UserState { + fn new() -> Self { + let (susp, handle) = Suspension::new(); + let value: Rc>> = Rc::default(); + + { + let value = value.clone(); + // we use async-std spawn local here. + task::spawn_local(async move { + let user = fetch_user().await; + { + let mut value = value.borrow_mut(); + *value = Some(user); + } + + handle.resume(); + }); + } + + Self { susp, value } + } +} + +#[hook] +fn use_user() -> SuspensionResult { + let user_state = use_state(UserState::new); + + let result = match *user_state.value.borrow() { + Some(ref user) => Ok(user.clone()), + None => Err(user_state.susp.clone()), + }; + + result +} + +#[function_component] +fn Content() -> HtmlResult { + let user = use_user()?; + + Ok(html! { +
+
{"Login name: "}{ user.login }
+
{"User name: "}{ user.name }
+
{"Blog: "}{ user.blog }
+
{"Location: "}{ user.location }
+
+ }) +} + +#[function_component] +fn App() -> Html { + let fallback = html! {
{"Loading..."}
}; + + html! { + + + + } +} + +async fn render(_: Request<()>) -> tide::Result { + let content = task::spawn_blocking(move || { + task::block_on(async { + let renderer = yew::ServerRenderer::::new(); + + renderer.render().await + }) + }) + .await; + + let resp_content = format!( + r#" + + + yew-ssr with tide example + + +

yew-ssr with tide example

+ {} + + + "#, + content + ); + + let mut resp = Response::new(StatusCode::Ok); + resp.set_body(resp_content); + resp.set_content_type(mime::HTML); + + Ok(resp.into()) +} + +#[async_std::main] +async fn main() -> Result<(), std::io::Error> { + let mut server = tide::new(); + server.at("/").get(render); + println!("You can view the website at: http://localhost:8080"); + server.listen("127.0.0.1:8080").await?; + Ok(()) +} diff --git a/examples/simple-ssr/yew-ssr-warp/Cargo.toml b/examples/simple-ssr/yew-ssr-warp/Cargo.toml new file mode 100644 index 00000000000..7781fad63c6 --- /dev/null +++ b/examples/simple-ssr/yew-ssr-warp/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "yew-ssr-warp" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +tokio = { version = "1.17.0", features = ["full"] } +warp = "0.3.2" +yew = { path = "../../../packages/yew", features = ["ssr"] } +reqwest = { version = "0.11.9", features = ["json"] } +serde = { version = "1.0.136", features = ["derive"] } +uuid = { version = "0.8.2", features = ["serde"] } diff --git a/examples/simple-ssr/yew-ssr-warp/README.md b/examples/simple-ssr/yew-ssr-warp/README.md new file mode 100644 index 00000000000..1c4a17b05f8 --- /dev/null +++ b/examples/simple-ssr/yew-ssr-warp/README.md @@ -0,0 +1,6 @@ +# Server-side Rendering with warp & reqwest + +This example demonstrates server-side rendering with warp & reqwest. + +Run `cargo run -p yew-ssr-warp` and navigate to http://localhost:8080/ to +view results. diff --git a/examples/simple_ssr/src/main.rs b/examples/simple-ssr/yew-ssr-warp/src/main.rs similarity index 98% rename from examples/simple_ssr/src/main.rs rename to examples/simple-ssr/yew-ssr-warp/src/main.rs index 58dbb0dda8d..8ccd5e8b401 100644 --- a/examples/simple_ssr/src/main.rs +++ b/examples/simple-ssr/yew-ssr-warp/src/main.rs @@ -17,6 +17,8 @@ struct UuidResponse { async fn fetch_uuid() -> Uuid { // reqwest works for both non-wasm and wasm targets. let resp = reqwest::get("https://httpbin.org/uuid").await.unwrap(); + println!("Status: {}", resp.status()); + let uuid_resp = resp.json::().await.unwrap(); uuid_resp.uuid diff --git a/examples/simple_ssr/Cargo.toml b/examples/simple_ssr/Cargo.toml deleted file mode 100644 index d4812fcc79b..00000000000 --- a/examples/simple_ssr/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "simple_ssr" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -tokio = { version = "1.15.0", features = ["full"] } -warp = "0.3" -yew = { path = "../../packages/yew", features = ["ssr"] } -reqwest = { version = "0.11.8", features = ["json"] } -serde = { version = "1.0.132", features = ["derive"] } -uuid = { version = "0.8.2", features = ["serde"] } diff --git a/examples/simple_ssr/README.md b/examples/simple_ssr/README.md deleted file mode 100644 index 95cf18b43ea..00000000000 --- a/examples/simple_ssr/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# Server-side Rendering Example - -This example demonstrates server-side rendering. - -Run `cargo run -p simple_ssr` and navigate to http://localhost:8080/ to -view results.