Struct ructe::StaticFiles
source · pub struct StaticFiles { /* private fields */ }
Expand description
Handler for static files.
Apart from handling templates for dynamic content, ructe also helps with constants for static content.
Most sites that need HTML templates also needs some static resources. Maybe one or several CSS files, some javascript, and / or pictures. A good way to reduce network round-trips is to use a far expires header to tell the browser it can cache those files and don’t need to check if they have changed. But what if the files do change? Then pretty much the only way to make sure the browser gets the updated file is to change the URL to the file as well.
Ructe can create content-dependent file names for static files.
If you have an image.png
, ructe may call it image-SomeHash.png
where SomeHash
is 8 url-safe base64 characters encoding 48 bits
of a md5 sum of the file.
Each static file will be available as a
StaticFile
struct instance in
your templates::statics
module.
Also, the const STATICS
array in the same module will contain a
reference to each of those instances.
Actually serving the file is a job for a web framework like iron, nickel or rocket, but ructe helps by packing the file contents into a constant struct that you can access from rust code.
§Overview
This section describes how to set up your project to serve static content using ructe.
To do this, the first step is to add a line in build.rs
telling
ructe to find and transpile your static files:
let mut ructe = Ructe::from_env()?;
ructe.statics()?.add_files("static")?;
Then you need to link to the encoded file.
For an image, you probably want to link it from an <img>
tag in
a template. That can be done like this:
@use super::statics::image_png;
@()
<img alt="Something" src="/static/@image_png.name">
So, what has happened here?
First, assuming the static
directory in your
$CARGO_MANIFEST_DIR
contained a file name image.png
, your
templates::statics
module (which is reachable as super::statics
from inside a template) will contain a
pub static image_png: StaticFile
which can be imported and used
in both templates and rust code.
A StaticFile
has a field named name
which is a &'static str
containing the name with the generated hash, image-SomeHash.png
.
The next step is that a browser actually sends a request for
/static/image-SomeHash.png
and your server needs to deliver it.
Here, things depend on your web framework, so we start with some
pseudo code.
Full examples for warp, gotham, nickel, and iron is
available in the ructe repository.
/// A hypothetical web framework calls this each /static/... request,
/// with the name component of the URL as the name argument.
fn serve_static(name: &str) -> Response {
if let Some(data) = StaticFile::get(name) {
Response::Ok(data.content)
} else {
Response::NotFound
}
}
The StaticFile::get
function returns the &'static StaticFile
for a given file name if the file exists.
This is a reference to the same struct that we used by the name
image_png
in the template.
Besides the name
field (which will be equal to the argument, or
get
would not have returned this StaticFile
), there is a
content: &'static [u8]
field which contains the actual file
data.
§Content-types
How to get the content type of static files.
Ructe has support for making the content-type of each static
file availiable using the
mime crate.
Since mime version 0.3.0 was a breaking change of how the
mime::Mime
type was implemented, and both Nickel and Iron
currently require the old version (0.2.x), ructe provides
support for both mime 0.2.x and mime 0.3.x with separate
feature flags.
§Mime 0.2.x
To use the mime 0.2.x support, enable the mime02
feature and
add mime 0.2.x as a dependency:
[build-dependencies]
ructe = { version = "^0.3.2", features = ["mime02"] }
[dependencies]
mime = "~0.2"
A Mime
as implemented in mime
version 0.2.x cannot be
created statically, so instead a StaticFile
provides
pub fn mime(&self) -> Mime
.
use templates::statics::image_png;
assert_eq!(format!("Type is {}", image_png.mime()),
"Type is image/png");
§Mime 0.3.x
To use the mime 0.3.x support, enable the mime3
feature and
add mime 0.3.x as a dependency:
[build-dependencies]
ructe = { version = "^0.3.2", features = ["mime03"] }
[dependencies]
mime = "~0.3"
From version 0.3, the mime
crates supports creating const
static Mime
objects, so with this feature, a StaticFile
simply has a pub mime: &'static Mime
field.
use templates::statics::image_png;
assert_eq!(format!("Type is {}", image_png.mime),
"Type is image/png");
Implementations§
source§impl StaticFiles
impl StaticFiles
sourcepub fn add_files(&mut self, indir: impl AsRef<Path>) -> Result<&mut Self>
pub fn add_files(&mut self, indir: impl AsRef<Path>) -> Result<&mut Self>
Add all files from a specific directory, indir
, as static files.
sourcepub fn add_files_as(
&mut self,
indir: impl AsRef<Path>,
to: &str,
) -> Result<&mut Self>
pub fn add_files_as( &mut self, indir: impl AsRef<Path>, to: &str, ) -> Result<&mut Self>
Add all files from a specific directory, indir
, as static files.
The to
string is used as a directory path of the resulting
urls, the file names are taken as is, without adding any hash.
This is usefull for resources used by preexisting javascript
packages, where it might be hard to change the used urls.
Note that some way of changing the url when the content
changes is still needed if you serve the files with far
expire, and using this method makes that your responsibility
rather than ructes.
Either the file may have hashed names as is, or you may use
the version number of a 3:rd party package as part of the to
parameter.
The to
parameter may be an empty string.
In that case, no extra slash is added.
sourcepub fn add_file(&mut self, path: impl AsRef<Path>) -> Result<&mut Self>
pub fn add_file(&mut self, path: impl AsRef<Path>) -> Result<&mut Self>
Add one specific file as a static file.
Create a name to use in the url like name-hash.ext
where
name and ext are the name and extension from path
and has is
a few url-friendly bytes from a hash of the file content.
sourcepub fn add_file_as(
&mut self,
path: impl AsRef<Path>,
url_name: &str,
) -> Result<&mut Self>
pub fn add_file_as( &mut self, path: impl AsRef<Path>, url_name: &str, ) -> Result<&mut Self>
Add one specific file as a static file.
Use url_name
in the url without adding any hash characters.
sourcepub fn add_file_data<P>(&mut self, path: P, data: &[u8]) -> Result<&mut Self>
pub fn add_file_data<P>(&mut self, path: P, data: &[u8]) -> Result<&mut Self>
Add a resource by its name and content, without reading an actual file.
The path
parameter is used only to create a file name, the actual
content of the static file will be the data
parameter.
A hash will be added to the file name, just as for
file-sourced statics.
§Examples
With the folloing code in build.rs
:
let mut statics = ructe.statics()?;
statics.add_file_data("black.css", b"body{color:black}\n");
A StaticFile
named black_css
will be defined in the
templates::statics
module of your crate:
assert_eq!(statics::black_css.name, "black-r3rltVhW.css");
sourcepub fn get_names(&self) -> &BTreeMap<String, String>
pub fn get_names(&self) -> &BTreeMap<String, String>
Get a mapping of names, from without hash to with.
let mut statics = ructe.statics()?;
statics.add_file_data("black.css", b"body{color:black}\n");
statics.add_file_data("blue.css", b"body{color:blue}\n");
assert_eq!(
statics.get_names().iter()
.map(|(a, b)| format!("{} -> {}", a, b))
.collect::<Vec<_>>(),
vec!["black_css -> black-r3rltVhW.css".to_string(),
"blue_css -> blue-GZGxfXag.css".to_string()],
);
Trait Implementations§
Auto Trait Implementations§
impl Freeze for StaticFiles
impl RefUnwindSafe for StaticFiles
impl Send for StaticFiles
impl Sync for StaticFiles
impl Unpin for StaticFiles
impl UnwindSafe for StaticFiles
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T> IntoEither for T
impl<T> IntoEither for T
source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moresource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read more