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