ssr/lib.rs
1#![deny(missing_docs)]
2
3//! ## Installation
4//! Add to your `Cargo.toml`:
5//!
6//! ```toml
7//! ssr = "0.0.5"
8//! ```
9//!
10//! And install node worker from `npm`:
11//!
12//! ```sh
13//! // using npm
14//! npm install --save ssr-rs
15//!
16//! // or yarn
17//! yarn add ssr-rs
18//! ```
19//!
20//! ## How it works
21//! On application start, you create an [`Ssr`](Ssr) instance. Under the hood, it spins up a
22//! Node.js worker ready to accept rendering requests. [`Ssr`](Ssr) instance should be stored in a
23//! web server's state, so handlers can access it during a handling of incoming requests.
24//!
25//! [`Ssr`](Ssr) exposes a single method [`render`](Ssr::render), which accepts [`Uri`](http::Uri)
26//! and serializable data as an input. If everything went smooth, it returns a rendered `String`.
27//! This string can be a plain HTML or an app-specific encoded object with additional
28//! metadata—whatever returned from a JS renderer, supplied by the app.
29//!
30//! ## Initialization
31//!
32//! ```rust
33//! let ssr =
34//! Ssr::new(
35//! SsrConfig {
36//! port: 9000,
37//! js_worker: PathBuf::from("./node_modules/ssr-rs/worker.js"),
38//! js_worker_log: JsWorkerLog::Verbose,
39//! global_js_renderer: Some(PathBuf::from("./js/ssr.js")),
40//! }
41//! );
42//! ```
43//!
44//! ### `port`
45//! A port that Node.js worker will be listening on.
46//!
47//! ### `js_worker`
48//! Path to Node.js worker installed from `npm`. It should be relative to the
49//! [`std::env::current_dir`](std::env::current_dir).
50//!
51//! ### `js_worker_log`
52//! Log verbosity of Node.js worker: either [`Minimal`](JsWorkerLog::Minimal) or
53//! [`Verbose`](JsWorkerLog::Verbose).
54//!
55//! ### `global_js_renderer`
56//! If your web app is a SPA (Single Page Application), then you should have a single entry point
57//! for all rendering requests. If it's the case, provide a path to this file here and it will be
58//! used by the worker to render all responses. Another option is to provide a JS renderer per
59//! request but keep in mind that it would introduce additional runtime overhead since JS module
60//! has to be required during a request as opposed to requiring it once on application startup.
61//!
62//! ## Rendering
63//! In request handlers, you need to get [`Ssr`](Ssr) instance from your server's state. Once you
64//! have it (as well as all the required data to handle the current request), call
65//! [`ssr.render`](Ssr::render) function with the following input:
66//! - [`Uri`](http::Uri): uri of the current request
67//! - `Data: impl Serialize`: anything that implements [`Serialize`](serde::Serialize)
68//! - [`JsRenderer`](JsRenderer): an enum that tells to use either a global JS renderer or a
69//! renderer specific to this request.
70//!
71//! ```rust
72//! let uri = req.uri();
73//! let data = db::get_data();
74//! match ssr.render(uri, &data, JsRenderer::Global).await {
75//! Ok(html) => HttpResponse::Ok().body(html),
76//! Err(error) => {
77//! error!("Error: {}", error);
78//! HttpResponse::InternalServerError().finish()
79//! }
80//! }
81//! ```
82
83#[macro_use]
84extern crate log;
85#[macro_use]
86extern crate serde_json;
87
88mod error;
89mod json;
90mod ssr;
91mod worker;
92
93pub use ssr::{JsRenderer, JsWorkerLog, Ssr, SsrConfig};