rocket_dyn_templates/lib.rs
1//! Dynamic templating engine support for Rocket.
2//!
3//! This crate adds support for dynamic template rendering to Rocket. It
4//! automatically discovers templates, provides a `Responder` to render
5//! templates, and automatically reloads templates when compiled in debug mode.
6//! At present, it supports [Handlebars] and [Tera].
7//!
8//! # Usage
9//!
10//! 1. Depend on `rocket_dyn_templates`. Enable the feature(s) corresponding
11//! to your templating engine(s) of choice:
12//!
13//! ```toml
14//! [dependencies.rocket_dyn_templates]
15//! version = "0.1.0"
16//! features = ["handlebars", "tera", "minijinja"]
17//! ```
18//!
19//! 2. Write your templates inside of the [configurable]
20//! `${ROCKET_ROOT}/templates`. The filename _must_ end with an extension
21//! corresponding to an enabled engine. The second-to-last extension should
22//! correspond to the file's type:
23//!
24//! | Engine | Extension | Example |
25//! |--------------|-----------|--------------------------------------------|
26//! | [Tera] | `.tera` | `${ROCKET_ROOT}/templates/index.html.tera` |
27//! | [Handlebars] | `.hbs` | `${ROCKET_ROOT}/templates/index.html.hbs` |
28//! | [MiniJinja] | `.j2` | `${ROCKET_ROOT}/templates/index.html.j2` |
29//!
30//! [configurable]: #configuration
31//! [Tera]: https://docs.rs/crate/tera/1
32//! [Handlebars]: https://docs.rs/crate/handlebars/6
33//! [MiniJinja]: https://docs.rs/minijinja/2
34//!
35//! 3. Attach `Template::fairing()` and return a [`Template`] from your routes
36//! via [`Template::render()`], supplying the name of the template file
37//! **minus the last two extensions**:
38//!
39//! ```rust
40//! # #[macro_use] extern crate rocket;
41//! use rocket_dyn_templates::{Template, context};
42//!
43//! #[get("/")]
44//! fn index() -> Template {
45//! Template::render("index", context! { field: "value" })
46//! }
47//!
48//! #[launch]
49//! fn rocket() -> _ {
50//! rocket::build().attach(Template::fairing())
51//! }
52//! ```
53//!
54//! ## Configuration
55//!
56//! This crate reads one configuration parameter from the configured figment:
57//!
58//! * `template_dir` (**default: `templates/`**)
59//!
60//! A path to a directory to search for template files in. Relative paths
61//! are considered relative to the configuration file, or there is no file,
62//! the current working directory.
63//!
64//! For example, to change the default and set `template_dir` to different
65//! values based on whether the application was compiled for debug or release
66//! from a `Rocket.toml` file (read by the default figment), you might write:
67//!
68//! ```toml
69//! [debug]
70//! template_dir = "static/templates"
71//!
72//! [release]
73//! template_dir = "/var/opt/www/templates"
74//! ```
75//!
76//! **Note:** `template_dir` defaults to `templates/`. It _does not_ need to be
77//! specified if the default suffices.
78//!
79//! See the [configuration chapter] of the guide for more information on
80//! configuration.
81//!
82//! [configuration chapter]: https://rocket.rs/master/guide/configuration
83//!
84//! ## Template Naming and Content-Types
85//!
86//! Templates are rendered by _name_ via [`Template::render()`], which returns a
87//! [`Template`] responder. The _name_ of the template is the path to the
88//! template file, relative to `template_dir`, minus at most two extensions.
89//!
90//! The `Content-Type` of the response is automatically determined by the
91//! non-engine extension using [`ContentType::from_extension()`]. If there is no
92//! such extension or it is unknown, `text/plain` is used.
93//!
94//! The following table contains examples:
95//!
96//! | template path | [`Template::render()`] call | content-type |
97//! |-----------------------------------------------|-----------------------------------|--------------|
98//! | {template_dir}/index.html.hbs | `render("index")` | HTML |
99//! | {template_dir}/index.tera | `render("index")` | `text/plain` |
100//! | {template_dir}/index.hbs | `render("index")` | `text/plain` |
101//! | {template_dir}/dir/index.hbs | `render("dir/index")` | `text/plain` |
102//! | {template_dir}/dir/data.json.tera | `render("dir/data")` | JSON |
103//! | {template_dir}/data.template.xml.hbs | `render("data.template")` | XML |
104//! | {template_dir}/subdir/index.template.html.hbs | `render("subdir/index.template")` | HTML |
105//!
106//! The recommended naming scheme is to use two extensions: one for the file
107//! type, and one for the template extension. This means that template
108//! extensions should look like: `.html.hbs`, `.html.tera`, `.xml.hbs`, and so
109//! on.
110//!
111//! [`ContentType::from_extension()`]: ../rocket/http/struct.ContentType.html#method.from_extension
112//!
113//! ### Rendering Context
114//!
115//! In addition to a name, [`Template::render()`] requires a context to use
116//! during rendering. The context can be any [`Serialize`] type that serializes
117//! to an `Object` (a dictionary) value. The [`context!`] macro can be used to
118//! create inline `Serialize`-able context objects.
119//!
120//! [`Serialize`]: rocket::serde::Serialize
121//!
122//! ```rust
123//! # #[macro_use] extern crate rocket;
124//! use rocket::serde::Serialize;
125//! use rocket_dyn_templates::{Template, context};
126//!
127//! #[get("/")]
128//! fn index() -> Template {
129//! // Using the `context! { }` macro.
130//! Template::render("index", context! {
131//! site_name: "Rocket - Home Page",
132//! version: 127,
133//! })
134//! }
135//!
136//! #[get("/")]
137//! fn index2() -> Template {
138//! #[derive(Serialize)]
139//! #[serde(crate = "rocket::serde")]
140//! struct IndexContext {
141//! site_name: &'static str,
142//! version: u8
143//! }
144//!
145//! // Using an existing `IndexContext`, which implements `Serialize`.
146//! Template::render("index", IndexContext {
147//! site_name: "Rocket - Home Page",
148//! version: 127,
149//! })
150//! }
151//! ```
152//!
153//! ### Discovery, Automatic Reloads, and Engine Customization
154//!
155//! As long as one of [`Template::fairing()`], [`Template::custom()`], or
156//! [`Template::try_custom()`] is [attached], any file in the configured
157//! `template_dir` ending with a known engine extension (as described in the
158//! [usage section](#usage)) can be rendered. The latter two fairings allow
159//! customizations such as registering helpers and templates from strings.
160//!
161//! _**Note:** Templates that are registered directly via [`Template::custom()`],
162//! use whatever name provided during that registration; no extensions are
163//! automatically removed._
164//!
165//! In debug mode (without the `--release` flag passed to `cargo`), templates
166//! are **automatically reloaded** from disk when changes are made. In release
167//! builds, template reloading is disabled to improve performance and cannot be
168//! enabled.
169//!
170//! [attached]: rocket::Rocket::attach()
171//!
172//! ### Metadata and Rendering to `String`
173//!
174//! The [`Metadata`] request guard allows dynamically querying templating
175//! metadata, such as whether a template is known to exist
176//! ([`Metadata::contains_template()`]), and to render templates to `String`
177//! ([`Metadata::render()`]).
178
179#![doc(html_root_url = "https://api.rocket.rs/master/rocket_dyn_templates")]
180#![doc(html_favicon_url = "https://rocket.rs/images/favicon.ico")]
181#![doc(html_logo_url = "https://rocket.rs/images/logo-boxed.png")]
182
183#[macro_use] extern crate rocket;
184
185#[doc(inline)]
186#[cfg(feature = "tera")]
187/// The tera templating engine library, reexported.
188pub use tera;
189
190#[doc(inline)]
191#[cfg(feature = "handlebars")]
192/// The handlebars templating engine library, reexported.
193pub use handlebars;
194
195#[doc(inline)]
196#[cfg(feature = "minijinja")]
197/// The minijinja templating engine library, reexported.
198pub use minijinja;
199
200#[doc(hidden)]
201pub use rocket::serde;
202
203mod engine;
204mod fairing;
205mod context;
206mod metadata;
207mod template;
208
209pub use engine::Engines;
210pub use metadata::Metadata;
211pub use template::Template;