Template minification
Some checks are pending
ci/woodpecker/push/publish Pipeline is pending
ci/woodpecker/pr/publish Pipeline is pending

* use dist/template when exists
* move the minification in config.rs
* load askama.toml for the templates dirs name
* extract the minification of file to minify_and_copy
This commit is contained in:
Mylloon 2023-04-09 16:58:21 +02:00
parent f368e57d7f
commit ea5ce83658
Signed by: Anri
GPG key ID: A82D63DFF8D1317F
3 changed files with 105 additions and 55 deletions

3
askama.toml Normal file
View file

@ -0,0 +1,3 @@
[general]
# Directories to search for templates, relative to the crate root.
dirs = ["dist/templates", "templates"]

View file

@ -1,5 +1,12 @@
use serde::Deserialize; use serde::Deserialize;
use std::fs; use std::{
fs::{self, read_to_string, remove_dir_all},
path::PathBuf,
};
use glob::glob;
use minify_html::{minify, Cfg};
use std::{fs::File, io::Write, path::Path};
#[derive(Deserialize, Clone, Default)] #[derive(Deserialize, Clone, Default)]
pub struct FileConfig { pub struct FileConfig {
@ -13,6 +20,17 @@ pub struct FileConfig {
#[derive(Clone)] #[derive(Clone)]
pub struct Config { pub struct Config {
pub fc: FileConfig, pub fc: FileConfig,
pub static_location: String,
}
#[derive(Deserialize)]
struct AskamaConfig {
general: AskamaConfigGeneral,
}
#[derive(Deserialize)]
struct AskamaConfigGeneral {
dirs: Vec<String>,
} }
impl FileConfig { impl FileConfig {
@ -63,10 +81,91 @@ fn get_file_config(file_path: &str) -> FileConfig {
} }
} }
fn get_askama_config() -> AskamaConfig {
toml::from_str(&read_to_string("askama.toml").unwrap()).unwrap()
}
pub fn get_config(file_path: &str) -> Config { pub fn get_config(file_path: &str) -> Config {
let internal_config = get_file_config(file_path); let internal_config = get_file_config(file_path);
let static_dir = "static".to_string();
let templates_dir = get_askama_config().general.dirs.last().unwrap().to_string();
let files_root = init(static_dir.clone(), templates_dir);
Config { Config {
fc: internal_config, fc: internal_config,
static_location: format!("{}/{}", files_root, static_dir),
}
}
fn init(static_dir: String, templates_dir: String) -> String {
let dist_folder = "dist".to_string();
// println!("static = {}/{}", dist_folder, static_dir);
// println!("templates = {}/{}", dist_folder, templates_dir);
// The static folder is minimized only in release mode
if cfg!(debug_assertions) {
// Be sure that we not gonna use the dist folder by deleting it
remove_dir_all(dist_folder).unwrap_or_default();
".".to_string()
} else {
let cfg = Cfg::spec_compliant();
// Static files
for entry in glob(&format!("{static_dir}/**/*.*")).unwrap() {
let path = entry.unwrap();
let path_with_dist = path
.to_string_lossy()
.replace(&static_dir, &format!("{dist_folder}/{static_dir}"));
minify_and_copy(&cfg, path, path_with_dist);
}
// Template files
for entry in glob(&format!("{templates_dir}/**/*.*")).unwrap() {
let path = entry.unwrap();
let path_with_dist = path
.to_string_lossy()
.replace(&templates_dir, &format!("{dist_folder}/{templates_dir}"));
minify_and_copy(&cfg, path, path_with_dist);
}
dist_folder
}
}
fn minify_and_copy(cfg: &Cfg, path: PathBuf, path_with_dist: String) {
// Create folders
let new_path = Path::new(&path_with_dist);
fs::create_dir_all(new_path.parent().unwrap()).unwrap();
let mut copy = true;
if let Some(ext) = path.extension() {
// List of files who should be minified
if ["html", "css", "js", "svg", "webmanifest", "xml"]
.iter()
.any(|item| ext.to_string_lossy().to_lowercase().contains(item))
{
// We won't copy, we'll minify
copy = false;
// Minify
let data = fs::read(&path).unwrap();
let minified = minify(&data, cfg);
// Write files
let file = File::create(&path_with_dist);
file.expect("Error when minify the file")
.write_all(&minified)
.unwrap();
}
}
if copy {
// If no minification is needed
fs::copy(path, path_with_dist).unwrap();
} }
} }

View file

@ -1,12 +1,6 @@
use actix_files::Files; use actix_files::Files;
use actix_web::{middleware::DefaultHeaders, web, App, HttpServer}; use actix_web::{middleware::DefaultHeaders, web, App, HttpServer};
use glob::glob; use std::io;
use minify_html::{minify, Cfg};
use std::{
fs::{self, File},
io::{self, Write},
path::Path,
};
mod config; mod config;
mod template; mod template;
@ -35,52 +29,6 @@ async fn main() -> io::Result<()> {
let addr = ("0.0.0.0", config.fc.port.unwrap()); let addr = ("0.0.0.0", config.fc.port.unwrap());
let static_folder = "static";
let dist_folder = format!("dist/{static_folder}");
// The static folder is minimized only in release mode
let folder = if cfg!(debug_assertions) {
format!("{static_folder}/")
} else {
let cfg = Cfg::spec_compliant();
for entry in glob(&format!("{static_folder}/**/*.*")).unwrap() {
let path = entry.unwrap();
let path_with_dist = path.to_string_lossy().replace(static_folder, &dist_folder);
// Create folders
let new_path = Path::new(&path_with_dist);
fs::create_dir_all(new_path.parent().unwrap()).unwrap();
let mut copy = true;
if let Some(ext) = path.extension() {
// List of files who should be minified
if ["html", "css", "js", "svg", "webmanifest", "xml"]
.iter()
.any(|item| ext.to_string_lossy().to_lowercase().contains(item))
{
// We won't copy, we'll minify
copy = false;
// Minify
let data = fs::read(&path).unwrap();
let minified = minify(&data, &cfg);
// Write files
let mut file = File::create(&path_with_dist)?;
file.write_all(&minified)?;
}
}
if copy {
// If no minification is needed
fs::copy(path, path_with_dist)?;
}
}
format!("{dist_folder}/")
};
println!( println!(
"Listening to {}://{}:{}", "Listening to {}://{}:{}",
config.clone().fc.scheme.unwrap(), config.clone().fc.scheme.unwrap(),
@ -103,7 +51,7 @@ async fn main() -> io::Result<()> {
.service(networks::page) .service(networks::page)
.service(portfolio::page) .service(portfolio::page)
.service(contrib::page) .service(contrib::page)
.service(Files::new("/", &folder)) .service(Files::new("/", config.static_location.clone()))
.default_service(web::to(not_found::page)) .default_service(web::to(not_found::page))
}) })
.bind(addr)? .bind(addr)?