feat: minification
#17
3 changed files with 105 additions and 55 deletions
3
askama.toml
Normal file
3
askama.toml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[general]
|
||||||
|
# Directories to search for templates, relative to the crate root.
|
||||||
|
dirs = ["dist/templates", "templates"]
|
101
src/config.rs
101
src/config.rs
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
56
src/main.rs
56
src/main.rs
|
@ -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)?
|
||||||
|
|
Loading…
Reference in a new issue