Add minify support (#1146)
* Doc add a missing arg to `get_taxonomy_url` (#1139) This feature is already exist, but not in the doc yet Related #766 * Add minify support * Add documentation * Code review * Fix error in documentation * Update minify-html to 0.3.6 * Move minify into write_content function * Fix multiple calls to minify() * Add test for minified output * Fix breaking test Co-authored-by: Ken <2770219+ken0x0a@users.noreply.github.com>
This commit is contained in:
parent
d571dea8c3
commit
0df3631b3d
12
Cargo.lock
generated
12
Cargo.lock
generated
|
@ -1320,6 +1320,17 @@ dependencies = [
|
||||||
"unicase",
|
"unicase",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "minify-html"
|
||||||
|
version = "0.3.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b917ef1eb405ca3b1a489608f36392f0718ff4740bbc6f7d89edd4ec4c869fb7"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"lazy_static",
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
version = "0.3.7"
|
version = "0.3.7"
|
||||||
|
@ -2177,6 +2188,7 @@ dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"library",
|
"library",
|
||||||
"link_checker",
|
"link_checker",
|
||||||
|
"minify-html",
|
||||||
"rayon",
|
"rayon",
|
||||||
"sass-rs",
|
"sass-rs",
|
||||||
"search",
|
"search",
|
||||||
|
|
|
@ -74,6 +74,8 @@ pub struct Config {
|
||||||
|
|
||||||
/// Whether to compile the `sass` directory and output the css files into the static folder
|
/// Whether to compile the `sass` directory and output the css files into the static folder
|
||||||
pub compile_sass: bool,
|
pub compile_sass: bool,
|
||||||
|
/// Whether to minify the html output
|
||||||
|
pub minify_html: bool,
|
||||||
/// Whether to build the search index for the content
|
/// Whether to build the search index for the content
|
||||||
pub build_search_index: bool,
|
pub build_search_index: bool,
|
||||||
/// A list of file glob patterns to ignore when processing the content folder. Defaults to none.
|
/// A list of file glob patterns to ignore when processing the content folder. Defaults to none.
|
||||||
|
@ -320,6 +322,7 @@ impl Default for Config {
|
||||||
hard_link_static: false,
|
hard_link_static: false,
|
||||||
taxonomies: Vec::new(),
|
taxonomies: Vec::new(),
|
||||||
compile_sass: false,
|
compile_sass: false,
|
||||||
|
minify_html: false,
|
||||||
mode: Mode::Build,
|
mode: Mode::Build,
|
||||||
build_search_index: false,
|
build_search_index: false,
|
||||||
ignored_content: Vec::new(),
|
ignored_content: Vec::new(),
|
||||||
|
|
|
@ -8,6 +8,7 @@ include = ["src/**/*"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tera = "1"
|
tera = "1"
|
||||||
glob = "0.3"
|
glob = "0.3"
|
||||||
|
minify-html = "0.3.6"
|
||||||
rayon = "1"
|
rayon = "1"
|
||||||
serde = "1"
|
serde = "1"
|
||||||
serde_derive = "1"
|
serde_derive = "1"
|
||||||
|
|
|
@ -11,6 +11,7 @@ use std::sync::{Arc, Mutex, RwLock};
|
||||||
|
|
||||||
use glob::glob;
|
use glob::glob;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
use minify_html::{truncate, Cfg};
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use tera::{Context, Tera};
|
use tera::{Context, Tera};
|
||||||
|
|
||||||
|
@ -445,6 +446,21 @@ impl Site {
|
||||||
html
|
html
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Minifies html content
|
||||||
|
fn minify(&self, html: String) -> Result<String> {
|
||||||
|
let cfg = &Cfg { minify_js: false };
|
||||||
|
let mut input_bytes = html.as_bytes().to_vec();
|
||||||
|
match truncate(&mut input_bytes, cfg) {
|
||||||
|
Ok(_len) => match std::str::from_utf8(&mut input_bytes) {
|
||||||
|
Ok(result) => Ok(result.to_string()),
|
||||||
|
Err(err) => bail!("Failed to convert bytes to string : {}", err),
|
||||||
|
},
|
||||||
|
Err(minify_error) => {
|
||||||
|
bail!("Failed to truncate html at character {}:", minify_error.position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Copy the main `static` folder and the theme `static` folder if a theme is used
|
/// Copy the main `static` folder and the theme `static` folder if a theme is used
|
||||||
pub fn copy_static_directories(&self) -> Result<()> {
|
pub fn copy_static_directories(&self) -> Result<()> {
|
||||||
// The user files will overwrite the theme files
|
// The user files will overwrite the theme files
|
||||||
|
@ -511,10 +527,19 @@ impl Site {
|
||||||
create_directory(¤t_path)?;
|
create_directory(¤t_path)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let final_content = if !filename.ends_with("html") || !self.config.minify_html {
|
||||||
|
content
|
||||||
|
} else {
|
||||||
|
match self.minify(content) {
|
||||||
|
Ok(minified_content) => minified_content,
|
||||||
|
Err(error) => bail!(error),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
match self.build_mode {
|
match self.build_mode {
|
||||||
BuildMode::Disk => {
|
BuildMode::Disk => {
|
||||||
let end_path = current_path.join(filename);
|
let end_path = current_path.join(filename);
|
||||||
create_file(&end_path, &content)?;
|
create_file(&end_path, &final_content)?;
|
||||||
}
|
}
|
||||||
BuildMode::Memory => {
|
BuildMode::Memory => {
|
||||||
let path = if filename != "index.html" {
|
let path = if filename != "index.html" {
|
||||||
|
@ -527,7 +552,7 @@ impl Site {
|
||||||
}
|
}
|
||||||
.trim_end_matches('/')
|
.trim_end_matches('/')
|
||||||
.to_owned();
|
.to_owned();
|
||||||
&SITE_CONTENT.write().unwrap().insert(path, content);
|
&SITE_CONTENT.write().unwrap().insert(path, final_content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -543,8 +568,12 @@ impl Site {
|
||||||
let output = page.render_html(&self.tera, &self.config, &self.library.read().unwrap())?;
|
let output = page.render_html(&self.tera, &self.config, &self.library.read().unwrap())?;
|
||||||
let content = self.inject_livereload(output);
|
let content = self.inject_livereload(output);
|
||||||
let components: Vec<&str> = page.path.split('/').collect();
|
let components: Vec<&str> = page.path.split('/').collect();
|
||||||
let current_path =
|
let current_path = self.write_content(
|
||||||
self.write_content(&components, "index.html", content, !page.assets.is_empty())?;
|
&components,
|
||||||
|
"index.html",
|
||||||
|
content,
|
||||||
|
!page.assets.is_empty(),
|
||||||
|
)?;
|
||||||
|
|
||||||
// Copy any asset we found previously into the same directory as the index.html
|
// Copy any asset we found previously into the same directory as the index.html
|
||||||
for asset in &page.assets {
|
for asset in &page.assets {
|
||||||
|
|
|
@ -712,6 +712,18 @@ fn can_build_site_custom_builtins_from_theme() {
|
||||||
assert!(file_contains!(public, "404.html", "Oops"));
|
assert!(file_contains!(public, "404.html", "Oops"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_build_site_with_html_minified() {
|
||||||
|
let (_, _tmp_dir, public) = build_site_with_setup("test_site", |mut site| {
|
||||||
|
site.config.minify_html = true;
|
||||||
|
(site, true)
|
||||||
|
});
|
||||||
|
|
||||||
|
assert!(&public.exists());
|
||||||
|
assert!(file_exists!(public, "index.html"));
|
||||||
|
assert!(file_contains!(public, "index.html", "<!DOCTYPE html><html lang=en><head><meta charset=UTF-8>"));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_ignore_markdown_content() {
|
fn can_ignore_markdown_content() {
|
||||||
let (_, _tmp_dir, public) = build_site("test_site");
|
let (_, _tmp_dir, public) = build_site("test_site");
|
||||||
|
|
|
@ -85,6 +85,9 @@ languages = []
|
||||||
# When set to "true", the Sass files in the `sass` directory are compiled.
|
# When set to "true", the Sass files in the `sass` directory are compiled.
|
||||||
compile_sass = false
|
compile_sass = false
|
||||||
|
|
||||||
|
# When set to "true", the HTML output files will be minified
|
||||||
|
minify_html = false
|
||||||
|
|
||||||
# A list of glob patterns specifying asset files to ignore when the content
|
# A list of glob patterns specifying asset files to ignore when the content
|
||||||
# directory is processed. Defaults to none, which means that all asset files are
|
# directory is processed. Defaults to none, which means that all asset files are
|
||||||
# copied over to the `public` directory.
|
# copied over to the `public` directory.
|
||||||
|
|
Loading…
Reference in a new issue