ssr_rs/
lib.rs

1#![doc(html_logo_url = "https://raw.githubusercontent.com/Valerioageno/ssr-rs/main/logo.png")]
2
3//!
4//! The crate aims to enable server side rendering on rust servers in the simplest and lightest way possible.
5//!
6//! It uses an embedded version of the [V8](https://v8.dev/) javascript engine (<a href="https://github.com/denoland/rusty_v8" target="_blank">rusty_v8</a>) to parse and evaluate a built bundle file and return a string with the rendered html.
7//!
8//! ℹ️ **This project is the backbone of [tuono](https://github.com/Valerioageno/tuono); a fullstack react framework with built in SSR.**
9//!
10//! Currently it works with [Vite](https://vitejs.dev/), [Webpack](https://webpack.js.org/), [Rspack](https://www.rspack.dev/), [React 18](https://react.dev/) and [Svelte 4](https://svelte.dev/) - Check the <a href="https://github.com/Valerioageno/ssr-rs/blob/main/examples" target="_blank">examples</a> folder.
11//!
12//! > Check <a href="https://github.com/Valerioageno/ssr-rs/blob/main/benches">here</a> the
13//! > benchmarks results.
14//!
15//!  # Getting started
16//! ```bash
17//! cargo add ssr_rs
18//! ```
19//!
20//!  # Example
21//!
22//! To render to string a bundled react project the application should perform the following
23//! calls.
24//!
25//! ```no_run
26//! use ssr_rs::Ssr;
27//! use std::fs::read_to_string;
28//!
29//! fn main() {
30//!     Ssr::create_platform();
31//!
32//!     let source = read_to_string("./path/to/build.js").unwrap();
33//!
34//!     let mut js = Ssr::from(source, "entryPoint").unwrap();
35//!
36//!     let html = js.render_to_string(None).unwrap();
37//!    
38//!     assert_eq!(html, "<!doctype html><html>...</html>".to_string());
39//! }
40//! ```
41//! ## What is the "entryPoint"?
42//!
43//! The `entryPoint` could be either:
44//! - the function that returns an object with one or more properties that are functions that when called return the rendered result
45//! - the object itself with one or more properties that are functions that when called return the rendered result
46//!
47//! In case the bundled JS is an IIFE or the plain object the `entryPoint` is an empty string.
48//!
49//! ```javascript
50//! // IIFE example | bundle.js -> See vite-react example
51//! (() => ({ renderToStringFn: (props) => "<html></html>" }))() // The entryPoint is an empty string
52//! ```
53
54//! ```javascript
55//! // Plain object example | bundle.js
56//! ({renderToStringFn: (props) => "<html></html>"}); // The entryPoint is an empty string
57//! ```
58
59//! ```javascript
60//! // IIFE variable example | bundle.js -> See webpack-react example
61//! var SSR = (() => ({renderToStringFn: (props) => "<html></html>"}))() // SSR is the entry point
62//! ```
63
64//! ```javascript
65//! // Variable example | bundle.js -> See webpack-react example
66//! var SSR = {renderToStringFn: (props) => "<html></html>"}; // SSR is the entry point
67//! ```
68//!
69//! > The exports results are managed by the bundler directly.
70//!
71//! # Example with initial props
72//!
73//! ```no_run
74//! use ssr_rs::Ssr;
75//! use std::fs::read_to_string;
76//!
77//! fn main() {
78//!     Ssr::create_platform();
79//!
80//!     let props = r##"{
81//!       "params": [
82//!            "hello",
83//!            "ciao",
84//!            "こんにちは"
85//!        ]
86//!     }"##;
87//!
88//!     let source = read_to_string("./path/to/build.js").unwrap();
89//!
90//!     let mut js = Ssr::from(source, "entryPoint").unwrap();
91//!
92//!     let html = js.render_to_string(Some(&props)).unwrap();
93//!    
94//!     assert_eq!(html, "<!doctype html><html>...</html>".to_string());
95//! }
96//!```
97//!
98//! # Example with actix-web
99//!
100//! > Examples with different web frameworks are available in the <a href="https://github.com/Valerioageno/ssr-rs/blob/main/examples" target="_blank">examples</a> folder.
101//!
102//! Even though the V8 engine allows accessing the same `isolate` from different threads that is forbidden by this crate for two reasons:
103//! 1. rusty_v8 library have not implemented yet the V8 Locker API. Accessing Ssr struct from a different thread will make the V8 engine to panic.
104//! 2. Rendering HTML does not need shared state across threads.
105//!
106//! For the reasons above parallel computation is a better choice. Following actix-web setup:
107//!
108//! ```no_run
109//! use actix_web::{get, http::StatusCode, App, HttpResponse, HttpServer};
110//! use std::cell::RefCell;
111//! use std::fs::read_to_string;
112//!
113//! use ssr_rs::Ssr;
114//!
115//! thread_local! {
116//!    static SSR: RefCell<Ssr<'static, 'static>> = RefCell::new(
117//!        Ssr::from(
118//!            read_to_string("./client/dist/ssr/index.js").unwrap(),
119//!            "SSR"
120//!            ).unwrap()
121//!    )
122//!}
123//!
124//! #[actix_web::main]
125//!async fn main() -> std::io::Result<()> {
126//!    Ssr::create_platform();
127//!
128//!    HttpServer::new(|| {
129//!        App::new()
130//!            .service(index)
131//!        })
132//!        .bind("127.0.0.1:8080")?
133//!        .run()
134//!        .await
135//! }
136//!
137//! #[get("/")]
138//! async fn index() -> HttpResponse {
139//!    let result = SSR.with(|ssr| ssr.borrow_mut().render_to_string(None).unwrap());
140//!
141//!    HttpResponse::build(StatusCode::OK)
142//!        .content_type("text/html; charset=utf-8")
143//!        .body(result)
144//! }
145//!```
146mod icu;
147mod ssr;
148
149pub use ssr::{Ssr, SsrError};
150pub use v8;