Skip to main content

cargo_leptos/ext/
compress.rs

1use crate::internal_prelude::*;
2use brotli::enc::BrotliEncoderParams;
3use libflate::gzip;
4use std::fs;
5use std::fs::File;
6use std::io::{BufReader, Write};
7use std::path::PathBuf;
8use tokio::time::Instant;
9
10pub async fn compress_static_files(path: PathBuf) -> Result<()> {
11    let start = Instant::now();
12
13    tokio::task::spawn_blocking(move || compress_dir_all(path)).await??;
14
15    info!(
16        "Precompression of static files finished after {} ms",
17        start.elapsed().as_millis()
18    );
19    Ok(())
20}
21
22// This is sync / blocking because an async / parallel execution did provide only a small benefit
23// in performance (~4%) while needing quite a few more dependencies and much more verbose code.
24fn compress_dir_all(path: PathBuf) -> Result<()> {
25    trace!("FS compress_dir_all {:?}", path);
26
27    let dir = fs::read_dir(&path).wrap_err(format!("Could not read {path:?}"))?;
28    let brotli_params = BrotliEncoderParams::default();
29
30    for entry in dir.into_iter() {
31        let path = entry?.path();
32        let metadata = fs::metadata(&path)?;
33
34        if metadata.is_dir() {
35            compress_dir_all(path)?;
36        } else {
37            let pstr = path.to_str().unwrap_or_default();
38            if pstr.ends_with(".gz") || pstr.ends_with(".br") {
39                // skip all files that are already compressed
40                continue;
41            }
42
43            let file = fs::read(&path)?;
44
45            // gzip
46            let mut encoder = gzip::Encoder::new(Vec::new())?;
47            encoder.write_all(file.as_ref())?;
48            let encoded_data = encoder.finish().into_result()?;
49            let path_gz = format!("{pstr}.gz");
50            fs::write(path_gz, encoded_data)?;
51
52            // brotli
53            let path_br = format!("{pstr}.br");
54            let mut output = File::create(path_br)?;
55            let mut reader = BufReader::new(file.as_slice());
56            brotli::BrotliCompress(&mut reader, &mut output, &brotli_params)?;
57        }
58    }
59
60    Ok(())
61}