diff --git a/Cargo.toml b/Cargo.toml index 19a15ee..3dcb32e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,10 @@ [package] name = "minify-html" -description = "Fast and smart HTML + JS minifier" +description = "Extremely fast and smart HTML + JS + CSS minifier" license = "MIT" homepage = "https://github.com/wilsonzlin/minify-html" readme = "README.md" -keywords = ["html", "compress", "minifier", "minify", "minification"] +keywords = ["html", "compress", "minifier", "js", "css"] categories = ["compression", "command-line-utilities", "development-tools::build-utils", "web-programming"] repository = "https://github.com/wilsonzlin/minify-html.git" version = "0.3.12" @@ -22,6 +22,6 @@ js-esbuild = ["crossbeam", "esbuild-rs"] [dependencies] aho-corasick = "0.7" crossbeam = { version = "0.7", optional = true } -esbuild-rs = { version = "0.2.1", optional = true } +esbuild-rs = { version = "0.8.30", optional = true } lazy_static = "1.4" memchr = "2" diff --git a/README.md b/README.md index 770567e..f71bbab 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Comes with native bindings to Node.js, Python, Java, and Ruby. - Advanced minification strategy beats other minifiers with only one pass. - Uses zero memory allocations, SIMD searching, direct tries, and lookup tables. - Well tested with a large test suite and extensive [fuzzing](./fuzz). -- Natively binds to [esbuild](https://github.com/wilsonzlin/esbuild-rs) for super fast JS minification. +- Natively binds to [esbuild](https://github.com/wilsonzlin/esbuild-rs) for super fast JS and CSS minification. ## Performance @@ -46,9 +46,9 @@ minify-html --src /path/to/src.html --out /path/to/output.min.html minify-html = { version = "0.3.12", features = ["js-esbuild"] } ``` -Building with the `js-esbuild` feature requires the Go compiler to be installed as well, to build the [JS minifier](https://github.com/wilsonzlin/esbuild-rs). +Building with the `js-esbuild` feature requires the Go compiler to be installed as well, to build the [JS and CSS minifier](https://github.com/wilsonzlin/esbuild-rs). -If the `js-esbuild` feature is not enabled, `cfg.minify_js` will have no effect. +If the `js-esbuild` feature is not enabled, `cfg.minify_js` and `cfg.minify_css` will have no effect. ##### Use @@ -82,7 +82,7 @@ yarn add @minify-html/js ```js const minifyHtml = require("@minify-html/js"); -const cfg = minifyHtml.createConfiguration({ minifyJs: false }); +const cfg = minifyHtml.createConfiguration({ minifyJs: false, minifyCss: false }); const minified = minifyHtml.minify("
Hello, world!
", cfg); // Alternatively, minify in place to avoid copying. @@ -97,7 +97,7 @@ minify-html is also available for TypeScript: import * as minifyHtml from "@minify-html/js"; import * as fs from "fs"; -const cfg = minifyHtml.createConfiguration({ minifyJs: false }); +const cfg = minifyHtml.createConfiguration({ minifyJs: false, minifyCss: false }); const minified = minifyHtml.minify("Hello, world!
", cfg); // Or alternatively: const minified = minifyHtml.minifyInPlace(fs.readFileSync("source.html"), cfg); @@ -133,6 +133,7 @@ import in.wilsonl.minifyhtml.SyntaxException; Configuration cfg = new Configuration.Builder() .setMinifyJs(false) + .setMinifyCss(false) .build(); try { @@ -165,7 +166,7 @@ Add the PyPI project as a dependency and install it using `pip` or `pipenv`. import minify_html try: - minified = minify_html.minify("Hello, world!
", minify_js=False) + minified = minify_html.minify("Hello, world!
", minify_js=False, minify_css=False) except SyntaxError as e: print(e) ``` @@ -188,7 +189,7 @@ Add the library as a dependency to `Gemfile` or `*.gemspec`. ```ruby require 'minify_html' -print MinifyHtml.minify("Hello, world!
", { :minify_js => false }) +print MinifyHtml.minify("Hello, world!
", { :minify_js => false, :minify_css => false }) ``` diff --git a/bench/README.md b/bench/README.md index e889c23..9cee574 100644 --- a/bench/README.md +++ b/bench/README.md @@ -41,7 +41,6 @@ Since speed depends on the input, speed charts show performance relative to the The settings used for each minifier can be found in [minifiers.js](./minifiers.js). Some settings to note: -- CSS minification is disabled for all, as minify-html currently does not support CSS minification (coming soon). - All minifiers are configured to use esbuild for JS minification asynchronously and in parallel, similar to how minify-html works. - `conservativeCollapse` is enabled for html-minifier as otherwise some whitespace would be unsafely removed with side effects. minify-html can safely remove whitespace with context if configured properly. diff --git a/bench/minifiers.js b/bench/minifiers.js index 292a84a..d04a5d8 100644 --- a/bench/minifiers.js +++ b/bench/minifiers.js @@ -1,9 +1,10 @@ +const cleanCss = require('clean-css'); const esbuild = require('esbuild'); const htmlMinifier = require('html-minifier'); const minifyHtml = require('@minify-html/js'); const minimize = require('minimize'); -const testJsMinification = process.env.HTML_ONLY !== '1'; +const testJsAndCssMinification = process.env.HTML_ONLY !== '1'; const jsMime = new Set([ undefined, @@ -46,7 +47,10 @@ class EsbuildAsync { } } -const minifyHtmlCfg = minifyHtml.createConfiguration({minifyJs: testJsMinification}); +const minifyHtmlCfg = minifyHtml.createConfiguration({ + minifyJs: testJsAndCssMinification, + minifyCss: testJsAndCssMinification, +}); const htmlMinifierCfg = { collapseBooleanAttributes: true, collapseInlineTagWhitespace: true, @@ -59,7 +63,8 @@ const htmlMinifierCfg = { decodeEntities: true, ignoreCustomComments: [], ignoreCustomFragments: [/<\?[\s\S]*?\?>/], - // This will be set to a function if `testJsMinification` is true. + // These will be set later if `testJsAndCssMinification` is true. + minifyCSS: false, minifyJS: false, processConditionalComments: true, removeAttributeQuotes: true, @@ -75,32 +80,42 @@ const htmlMinifierCfg = { module.exports = { '@minify-html/js': (_, buffer) => minifyHtml.minifyInPlace(Buffer.from(buffer), minifyHtmlCfg), - 'html-minifier': testJsMinification + 'html-minifier': testJsAndCssMinification ? async (content) => { const js = new EsbuildAsync(); const res = htmlMinifier.minify(content, { ...htmlMinifierCfg, + minifyCSS: true, minifyJS: code => js.queue(code), }); return js.finalise(res); } : content => htmlMinifier.minify(content, htmlMinifierCfg), - 'minimize': testJsMinification + 'minimize': testJsAndCssMinification ? async (content) => { const js = new EsbuildAsync(); - const plugins = []; - if (testJsMinification) { - plugins.push({ - id: 'esbuild', - element: (node, next) => { - if (node.type === 'text' && node.parent && node.parent.type === 'script' && jsMime.has(node.parent.attribs.type)) { - node.data = js.queue(node.data); - } - next(); + const css = new cleanCss({ + level: 2, + inline: false, + rebase: false, + }); + const res = new minimize({ + plugins: [ + { + id: 'esbuild', + element: (node, next) => { + if (node.type === 'text' && node.parent) { + if (node.parent.type === 'script' && jsMime.has(node.parent.attribs.type)) { + node.data = js.queue(node.data); + } else if (node.parent.type === 'style') { + node.data = css.minify(node.data).styles; + } + } + next(); + }, }, - }); - } - const res = new minimize({plugins}).parse(content); + ], + }).parse(content); return js.finalise(res); } : content => new minimize().parse(content), diff --git a/bench/minify-html-bench/src/main.rs b/bench/minify-html-bench/src/main.rs index 1aa67ae..46fbc5a 100644 --- a/bench/minify-html-bench/src/main.rs +++ b/bench/minify-html-bench/src/main.rs @@ -25,6 +25,7 @@ fn main() { let mut data = source.to_vec(); in_place(&mut data, &Cfg { minify_js: false, + minify_css: false, }).unwrap(); }; let elapsed = start.elapsed().as_secs_f64(); diff --git a/bench/package.json b/bench/package.json index c3eda9d..19fe34b 100644 --- a/bench/package.json +++ b/bench/package.json @@ -5,6 +5,7 @@ "benchmark": "2.1.4", "chart.js": "^2.9.3", "chartjs-node": "^1.7.1", + "clean-css": "^4.2.3", "esbuild": "^0.6.5", "html-minifier": "4.0.0", "minimize": "2.2.0", diff --git a/cli/src/main.rs b/cli/src/main.rs index e07e7cc..0ffbedf 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -13,6 +13,8 @@ struct Cli { out: Option