diff --git a/bench/runners/minify-html-onepass/Cargo.toml b/bench/runners/minify-html-onepass/Cargo.toml index 9c8ba4c..485dafc 100644 --- a/bench/runners/minify-html-onepass/Cargo.toml +++ b/bench/runners/minify-html-onepass/Cargo.toml @@ -6,6 +6,6 @@ authors = ["Wilson Lin "] edition = "2018" [dependencies] -minify-html-onepass = { path = "../../../rust/onepass", features = ["js-esbuild"] } +minify-html-onepass = { path = "../../../rust/onepass" } serde = { version = "1.0.104", features = ["derive"] } serde_json = "1.0.44" diff --git a/rust/onepass/Cargo.toml b/rust/onepass/Cargo.toml index 34a902e..8ef8567 100644 --- a/rust/onepass/Cargo.toml +++ b/rust/onepass/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "minify-html-onepass" -description = "Alternate version of minify-html" +description = "Even faster version of minify-html" license = "MIT" homepage = "https://github.com/wilsonzlin/minify-html" readme = "README.md" @@ -15,13 +15,9 @@ include = ["/src/**/*", "/Cargo.toml", "/LICENSE", "/README.md"] [badges] maintenance = { status = "actively-developed" } -[features] -default = [] -js-esbuild = ["crossbeam", "esbuild-rs"] - [dependencies] aho-corasick = "0.7" -crossbeam = { version = "0.7", optional = true } -esbuild-rs = { version = "0.13.8", optional = true } +css-minify = "0.2.2" lazy_static = "1.4" memchr = "2" +minify-js = "0.1.0" diff --git a/rust/onepass/src/cfg/mod.rs b/rust/onepass/src/cfg/mod.rs index 54a7f96..06a7017 100644 --- a/rust/onepass/src/cfg/mod.rs +++ b/rust/onepass/src/cfg/mod.rs @@ -2,17 +2,14 @@ /// minification approach. pub struct Cfg { /// If enabled, JavaScript in ` - // /* - // Considerations: - // - Need to parse strings (e.g. "", '', ``) so syntax within strings aren't mistakenly interpreted as code. - // - Need to be able to parse regex literals to determine string delimiters aren't actually characters in the regex. - // - Determining whether a slash is division or regex requires a full-blown JS parser to handle all cases (this is a well-known JS parsing problem). - // - `/::new(); - // SCRIPT_END must be case insensitive. - SCRIPT_END.replace_all_with_bytes( - result.code.as_str().trim().as_bytes(), - &mut escaped, - |_, orig, dst| { - dst.extend(b"<\\/"); - // Keep original case. - dst.extend(&orig[2..]); - true - }, - ); - guard.push(EsbuildSection { src, escaped }); - // Drop Arc reference and Mutex guard before marking task as complete as it's possible proc::finish - // waiting on WaitGroup will resume before Arc/Mutex is dropped after exiting this function. - drop(guard); - drop(results); - drop(wg); - }, - ); + // TODO Write to `out` directly, but only if we can guarantee that the length will never exceed the input. + let mut output = Vec::new(); + let result = minify_js::minify(proc[src].to_vec(), &mut output); + // TODO Collect error as warning. + if !result.is_err() && output.len() < src.len() { + proc.write_slice(output.as_slice()); + } else { + proc.write_range(src); }; + } else { + proc.write_range(src); }; Ok(()) diff --git a/rust/onepass/src/unit/style.rs b/rust/onepass/src/unit/style.rs index ca2f671..c84d2a3 100644 --- a/rust/onepass/src/unit/style.rs +++ b/rust/onepass/src/unit/style.rs @@ -1,32 +1,16 @@ use aho_corasick::{AhoCorasick, AhoCorasickBuilder}; +use css_minify::optimizations::{Level, Minifier}; use lazy_static::lazy_static; -#[cfg(feature = "js-esbuild")] -use { - crate::proc::checkpoint::WriteCheckpoint, - crate::proc::EsbuildSection, - esbuild_rs::{Loader, TransformOptions, TransformOptionsBuilder}, - std::sync::Arc, -}; +use std::str::from_utf8_unchecked; use crate::err::ProcessingResult; +use crate::proc::checkpoint::WriteCheckpoint; use crate::proc::MatchAction::*; use crate::proc::MatchMode::*; use crate::proc::Processor; use crate::Cfg; -#[cfg(feature = "js-esbuild")] -lazy_static! { - static ref TRANSFORM_OPTIONS: Arc = { - let mut builder = TransformOptionsBuilder::new(); - builder.loader = Loader::CSS; - builder.minify_identifiers = true; - builder.minify_syntax = true; - builder.minify_whitespace = true; - builder.build() - }; -} - lazy_static! { static ref STYLE_END: AhoCorasick = AhoCorasickBuilder::new() .ascii_case_insensitive(true) @@ -35,45 +19,23 @@ lazy_static! { #[inline(always)] pub fn process_style(proc: &mut Processor, cfg: &Cfg) -> ProcessingResult<()> { - #[cfg(feature = "js-esbuild")] let start = WriteCheckpoint::new(proc); proc.require_not_at_end()?; - proc.m(WhileNotSeq(&STYLE_END), Keep); + let src = proc.m(WhileNotSeq(&STYLE_END), Discard); // `process_tag` will require closing tag. - // TODO This is copied from script.rs. - #[cfg(feature = "js-esbuild")] if cfg.minify_css { - let (wg, results) = proc.new_esbuild_section(); - let src = start.written_range(proc); - unsafe { - esbuild_rs::transform_direct_unmanaged( - &proc[src], - &TRANSFORM_OPTIONS.clone(), - move |result| { - let mut guard = results.lock().unwrap(); - // TODO Are there other places that can have unintentional closing tags? - let mut escaped = Vec::::new(); - // STYLE_END must be case insensitive. - STYLE_END.replace_all_with_bytes( - result.code.as_str().trim().as_bytes(), - &mut escaped, - |_, orig, dst| { - dst.extend(b"<\\/"); - // Keep original case. - dst.extend(&orig[2..]); - true - }, - ); - guard.push(EsbuildSection { src, escaped }); - // Drop Arc reference and Mutex guard before marking task as complete as it's possible proc::finish - // waiting on WaitGroup will resume before Arc/Mutex is dropped after exiting this function. - drop(guard); - drop(results); - drop(wg); - }, - ); + let result = Minifier::default() + .minify(unsafe { from_utf8_unchecked(&proc[src]) }, Level::Three) + .ok(); + // TODO Collect error as warning. + if result.as_ref().filter(|r| r.len() < src.len()).is_some() { + proc.write_slice(result.unwrap().as_bytes()); + } else { + proc.write_range(src); }; + } else { + proc.write_range(src); }; Ok(()) diff --git a/version b/version index 9f28f9d..a9e4637 100755 --- a/version +++ b/version @@ -93,9 +93,7 @@ if ( cmd("git", "pull"); cmd("bash", "./prebuild.sh"); cmd("cargo", "test", { workingDir: RUST_MAIN_DIR }); -cmd("cargo", "test", "--features", "js-esbuild", { - workingDir: RUST_ONEPASS_DIR, -}); +cmd("cargo", "test", { workingDir: RUST_ONEPASS_DIR }); for (const f of [ `${RUST_MAIN_DIR}/Cargo.toml`,