Closed sebadob closed 8 months ago
I did some testing today and used this version instead of the "original" cargo-leptos
for the development and it works out very nicely so far.
The idea is, that you can specify the -P
or --precompress
flag, when you do a build -r
or serve -r
. This will precompress all static assets with gzip (for compatibility) and brotli. This greatly reduces the assets sizes of course and since these are static files, there is no need for a framework like axum or actix to do this compression each time over and over again with each request, when the results are static anyway.
What I am doing on my project is that am using rust_embed
for embed the precompressed assets into the final binary for even better performance. You can either serve the precompressed files with a manual handler, for instance something like this:
use axum::body::Body;
use axum::extract::State;
use axum::{
body::{boxed, Full},
http::{header, Response, StatusCode},
response,
};
use common::constants::DEV_MODE;
use http::{Request, Uri};
use leptos::*;
use std::borrow::Cow;
use tracing::{error, info};
#[derive(rust_embed::RustEmbed)]
#[folder = "../target/site/"]
struct Assets;
pub async fn file_and_error_handler(
uri: Uri,
State(_options): State<LeptosOptions>,
req: Request<Body>,
) -> response::Response {
let (_, path) = uri.path().split_at(1); // split off the first `/`
let mime = mime_guess::from_path(path);
let accept_encoding = req
.headers()
.get("accept-encoding")
.map(|h| h.to_str().unwrap_or("none"))
.unwrap_or("none");
let (path, encoding) = if *DEV_MODE {
// during DEV, don't care about the precompression -> faster workflow
(Cow::from(path), "none")
} else if accept_encoding.contains("br") {
(Cow::from(format!("{}.br", path)), "br")
} else if accept_encoding.contains("gzip") {
(Cow::from(format!("{}.gz", path)), "gzip")
} else {
(Cow::from(path), "none")
};
match Assets::get(path.as_ref()) {
Some(content) => {
let body = boxed(Full::from(content.data));
match *DEV_MODE {
true => Response::builder()
.header(header::CONTENT_TYPE, mime.first_or_octet_stream().as_ref())
.header(header::CONTENT_ENCODING, encoding)
.body(body)
.unwrap(),
false => {
Response::builder()
.header(header::CACHE_CONTROL, "max-age=86400")
.header(header::CONTENT_TYPE, mime.first_or_octet_stream().as_ref())
.header(header::CONTENT_ENCODING, encoding)
.body(body)
.unwrap()
}
}
}
None => {
error!(">> Asset {} not found", path);
for a in Assets::iter() {
info!("Available asset: {}", a);
}
Response::builder()
.status(StatusCode::NOT_FOUND)
.body(boxed(Full::from("not found")))
.unwrap()
}
}
}
Or if you do not want to directly embed the assets, with axum you can simply add somehting like this in your router:
ServeDir::new("../target/site/")
.precompressed_br()
.precompressed_gzip(),
For actix, there is an open issue to make it work just like with axum.
You can build or serve with this feature easily with cargo leptos build -r -P
, which will then result in something like this:
This precompression will be applied for --release
builds only. It does not provide any advantage in local development, it would just slow down recompliation.
Afternoon! This seem slike a very cool feature, what's the status on this?
It's working perfectly fine, ready for review / merge. I just don't have the rights to merge it into master.
The conflicts on the Cargo.lock
came up because a lot of other stuff was merged beforehand which updated the dependencies, and there were multiple. Someone with rights needs to "click the button".
Sorry for the long delay! I've been head down on 0.5 in my Leptos time for a while now, but have been reviewing this and the other open PRs and will be releasing a new version soon. Thanks so much for your work.
This is about adding a build step for
cargo-leptos
which does an optional precompression of the static assets in release build mode.This provides a huge performance boost both on the server, which does not need to dynamically compress static files for each request, and in transit to the client, if the server does not do compression in some middleware. Additionally, it allows an easy embedding of precompressed static assets into the final binary itself, which improves the performance even further.
I have a first (still incomplete) implementation and will update the description after some testing.