A Rust library for compressing and embedding static assets in a web server using Axum. This crate provides efficient asset embedding with optional compression (gzip and zstd) and conditional requests support.
-
Embed static assets at compile-time for efficient serving
-
Automatic compression with
gzipandzstd -
ETag support for conditional requests and caching
-
Seamless Axum integration with request extraction for encoding and caching headers
Add the following to your Cargo.toml:
[dependencies]
static-serve = "0.4"
axum = "0.8"Use the embed_assets! macro to create a static_router() function in scope which will include your static files, embedding them into your binary:
use static_serve::embed_assets;
embed_assets!("assets", compress = true, ignore_paths = ["temp.txt","temp"], cache_busted_paths = ["immutable"]);
let router = static_router();This will:
- Include all files from the
assetsdirectory excepttemp.txtand thetempdirectory - Compress them using
gzipandzstd(if beneficial) - For only files in
assets/immutable, add aCache-Controlheader withpublic, max-age=31536000, immutable(since these are marked as cache-busted paths) - Generate a
static_router()function to serve these assets
path_to_dir- a valid&strstring literal of the path to the static files to be included
-
compress = false- compress static files with zstd and gzip, true or false (defaults to false) -
ignore_paths = ["my_ignore_dir", "other_ignore_dir", "my_ignore_file.txt"]- a bracketed list of&strs of paths/subdirectories/files inside the target directory, which should be ignored and not included. (If this parameter is missing, no paths/subdirectories/files will be ignored) -
strip_html_ext = false- strips the.htmlor.htmfrom all HTML files included. If the filename isindex.htmlorindex.htm, theindexpart will also be removed, leaving just the root (defaults to false) -
cache_busted_paths = ["my_immutables_dir", "my_immutable_file"]- a bracketed list of&strs of the subdirectories and/or single files which should gain theCache-Controlheader withpublic, max-age=31536000, immutablefor cache-busted paths. If this parameter is missing, the default is that no embedded files will have theCache-Controlheader. Note: the files incache_busted_pathsneed to already be compatible with cache-busting by having hashes in their file paths (for example). Allstatic-servedoes is set the appropriate header.
Use the embed_asset! macro to return a function you can use as a GET handler, which will include your static file, embedded into your binary:
use axum::Router;
use static_serve::embed_asset;
let router: Router<()> = Router::new();
let handler = embed_asset!("assets/my_file.png", compress = true, cache_bust = true);
let router = router.route("/my_file.png", handler);This will:
- Include the file
my_file.pngfrom theassetsdirectory - Compress it using
gzipandzstd(if beneficial) - Add a
Cache-Controlheader with the valuepublic, max-age=31536000, immutablefor cache-busted paths. Note: the file inembed_asset!needs to already be compatible with cache-busting by having a hash in its file path (for example). Allstatic-servedoes is set the appropriate header. - Generate a
MethodRouter"handler" you can add as a route on your router to serve the file
path_to_file- a valid&strstring literal of the path to the static file to be included
compress = false- compress a static file with zstd and gzip, true or false (defaults to false)cache_bust = false- add aCache-Controlheader with the valuepublic, max-age=31536000, immutablefor a cache-busted asset (defaults to false)
The crate automatically handles:
-
Accept-Encodingheader to serve compressed versions if available -
If-None-Matchheader for ETag validation, returning304 Not Modifiedif unchanged -
With the optional cache-bust headers feature, each embedded file in the
cache_busted_pathsarray (or single file in the case ofembed_asset!withcache_bust = true) will be returned with aCache-Controlheader with the valuepublic, max-age=31536000, immutable. Note: the files involved need to already be compatible with cache-busting by having hashes in their file paths (for example). Allstatic-servedoes is set the appropriate header.
use axum::{Router, Server};
use static_serve::{embed_assets, embed_asset};
embed_assets!("public", compress = true);
#[tokio::main]
async fn main() {
let router = static_router();
let my_file_handler = embed_asset!("other_files/my_file.txt");
let router = router.route("/other_files/my_file.txt", my_file_handler);
Server::bind(&"0.0.0.0:3000".parse().unwrap())
.serve(router.into_make_service())
.await
.unwrap();
}Licensed under either of
- Apache License, Version 2.0, (LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or https://opensource.org/licenses/MIT)
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.