Change default CSS minifier optimising level and allow configuring it
This commit is contained in:
parent
d4e0887465
commit
ad21466d2c
|
@ -1,5 +1,10 @@
|
|||
# minify-html changelog
|
||||
|
||||
## Pending
|
||||
|
||||
- Change the default CSS minifier optimisation level to 1, as higher levels may perform dangerous optimisations.
|
||||
- Allow configuring the CSS minifier optimisation level.
|
||||
|
||||
## 0.10.8
|
||||
|
||||
- [Node.js] Fix assertion failure panic on invalid argument type.
|
||||
|
|
|
@ -31,6 +31,18 @@ struct Cli {
|
|||
#[structopt(long)]
|
||||
minify_css: bool,
|
||||
|
||||
/// Use optimisation level 1 for the CSS minifier.
|
||||
#[structopt(long)]
|
||||
minify_css_level_1: bool,
|
||||
|
||||
/// Use optimisation level 2 for the CSS minifier. May perform some dangerous optimisations.
|
||||
#[structopt(long)]
|
||||
minify_css_level_2: bool,
|
||||
|
||||
/// Use optimisation level 3 for the CSS minifier. May perform many dangerous optimisations.
|
||||
#[structopt(long)]
|
||||
minify_css_level_3: bool,
|
||||
|
||||
#[structopt(long)]
|
||||
/// Do not minify DOCTYPEs. Minified DOCTYPEs may not be spec compliant.
|
||||
do_not_minify_doctype: bool,
|
||||
|
@ -92,6 +104,9 @@ fn main() {
|
|||
keep_html_and_head_opening_tags: args.keep_html_and_head_opening_tags,
|
||||
keep_spaces_between_attributes: args.keep_spaces_between_attributes,
|
||||
minify_css: args.minify_css,
|
||||
minify_css_level_1: args.minify_css_level_1,
|
||||
minify_css_level_2: args.minify_css_level_2,
|
||||
minify_css_level_3: args.minify_css_level_3,
|
||||
minify_js: args.minify_js,
|
||||
remove_bangs: args.remove_bangs,
|
||||
remove_processing_instructions: args.remove_processing_instructions,
|
||||
|
|
|
@ -11,6 +11,9 @@ public class Configuration {
|
|||
public final boolean keep_html_and_head_opening_tags;
|
||||
public final boolean keep_spaces_between_attributes;
|
||||
public final boolean minify_css;
|
||||
public final boolean minify_css_level_1;
|
||||
public final boolean minify_css_level_2;
|
||||
public final boolean minify_css_level_3;
|
||||
public final boolean minify_js;
|
||||
public final boolean remove_bangs;
|
||||
public final boolean remove_processing_instructions;
|
||||
|
@ -23,6 +26,9 @@ public class Configuration {
|
|||
boolean keep_html_and_head_opening_tags,
|
||||
boolean keep_spaces_between_attributes,
|
||||
boolean minify_css,
|
||||
boolean minify_css_level_1,
|
||||
boolean minify_css_level_2,
|
||||
boolean minify_css_level_3,
|
||||
boolean minify_js,
|
||||
boolean remove_bangs,
|
||||
boolean remove_processing_instructions
|
||||
|
@ -34,6 +40,9 @@ public class Configuration {
|
|||
this.keep_html_and_head_opening_tags = keep_html_and_head_opening_tags;
|
||||
this.keep_spaces_between_attributes = keep_spaces_between_attributes;
|
||||
this.minify_css = minify_css;
|
||||
this.minify_css_level_1 = minify_css_level_1;
|
||||
this.minify_css_level_2 = minify_css_level_2;
|
||||
this.minify_css_level_3 = minify_css_level_3;
|
||||
this.minify_js = minify_js;
|
||||
this.remove_bangs = remove_bangs;
|
||||
this.remove_processing_instructions = remove_processing_instructions;
|
||||
|
@ -50,6 +59,9 @@ public class Configuration {
|
|||
private boolean keep_html_and_head_opening_tags = false;
|
||||
private boolean keep_spaces_between_attributes = false;
|
||||
private boolean minify_css = false;
|
||||
private boolean minify_css_level_1 = false;
|
||||
private boolean minify_css_level_2 = false;
|
||||
private boolean minify_css_level_3 = false;
|
||||
private boolean minify_js = false;
|
||||
private boolean remove_bangs = false;
|
||||
private boolean remove_processing_instructions = false;
|
||||
|
@ -89,6 +101,21 @@ public class Configuration {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder setMinifyCssLevel1(boolean val) {
|
||||
this.minify_css_level_1 = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setMinifyCssLevel2(boolean val) {
|
||||
this.minify_css_level_2 = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setMinifyCssLevel3(boolean val) {
|
||||
this.minify_css_level_3 = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setMinifyJs(boolean val) {
|
||||
this.minify_js = val;
|
||||
return this;
|
||||
|
@ -114,6 +141,9 @@ public class Configuration {
|
|||
this.keep_html_and_head_opening_tags,
|
||||
this.keep_spaces_between_attributes,
|
||||
this.minify_css,
|
||||
this.minify_css_level_1,
|
||||
this.minify_css_level_2,
|
||||
this.minify_css_level_3,
|
||||
this.minify_js,
|
||||
this.remove_bangs,
|
||||
this.remove_processing_instructions
|
||||
|
|
|
@ -28,6 +28,18 @@ export function minify(
|
|||
* If enabled, CSS in `<style>` tags and `style` attributes will be minified.
|
||||
*/
|
||||
minify_css?: boolean;
|
||||
/**
|
||||
* Use optimisation level 1 for the CSS minifier. This is currently the default, but may change in the future if higher levels become safe.
|
||||
*/
|
||||
minify_css_level_1?: boolean;
|
||||
/**
|
||||
* Use optimisation level 2 for the CSS minifier. This is mostly safe, but may perform some dangerous optimisations.
|
||||
*/
|
||||
minify_css_level_2?: boolean;
|
||||
/**
|
||||
* Use optimisation level 3 for the CSS minifier. This performs many dangerous optimisations, so ensure any input works with this level.
|
||||
*/
|
||||
minify_css_level_3?: boolean;
|
||||
/** Remove all bangs. */
|
||||
remove_bangs?: boolean;
|
||||
/** Remove all processing_instructions. */
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
use neon::prelude::*;
|
||||
use neon::types::buffer::TypedArray;
|
||||
|
||||
macro_rules! get_bool {
|
||||
($cx:expr, $opt:expr, $name:literal) => {
|
||||
$opt.get_opt::<JsBoolean, _, _>(&mut $cx, $name)?
|
||||
.map(|v| v.value(&mut $cx))
|
||||
.unwrap_or(false)
|
||||
};
|
||||
}
|
||||
|
||||
fn minify(mut cx: FunctionContext) -> JsResult<JsBuffer> {
|
||||
let Ok(src) = cx.try_catch(|cx| cx.argument::<JsBuffer>(0)) else {
|
||||
return cx.throw_type_error("the first argument is not a Buffer");
|
||||
|
@ -9,46 +17,23 @@ fn minify(mut cx: FunctionContext) -> JsResult<JsBuffer> {
|
|||
return cx.throw_type_error("the second argument is not an object");
|
||||
};
|
||||
let cfg = minify_html::Cfg {
|
||||
do_not_minify_doctype: opt
|
||||
.get_opt::<JsBoolean, _, _>(&mut cx, "do_not_minify_doctype")?
|
||||
.map(|v| v.value(&mut cx))
|
||||
.unwrap_or(false),
|
||||
ensure_spec_compliant_unquoted_attribute_values: opt
|
||||
.get_opt::<JsBoolean, _, _>(&mut cx, "ensure_spec_compliant_unquoted_attribute_values")?
|
||||
.map(|v| v.value(&mut cx))
|
||||
.unwrap_or(false),
|
||||
keep_closing_tags: opt
|
||||
.get_opt::<JsBoolean, _, _>(&mut cx, "keep_closing_tags")?
|
||||
.map(|v| v.value(&mut cx))
|
||||
.unwrap_or(false),
|
||||
keep_html_and_head_opening_tags: opt
|
||||
.get_opt::<JsBoolean, _, _>(&mut cx, "keep_html_and_head_opening_tags")?
|
||||
.map(|v| v.value(&mut cx))
|
||||
.unwrap_or(false),
|
||||
keep_spaces_between_attributes: opt
|
||||
.get_opt::<JsBoolean, _, _>(&mut cx, "keep_spaces_between_attributes")?
|
||||
.map(|v| v.value(&mut cx))
|
||||
.unwrap_or(false),
|
||||
keep_comments: opt
|
||||
.get_opt::<JsBoolean, _, _>(&mut cx, "keep_comments")?
|
||||
.map(|v| v.value(&mut cx))
|
||||
.unwrap_or(false),
|
||||
minify_css: opt
|
||||
.get_opt::<JsBoolean, _, _>(&mut cx, "minify_css")?
|
||||
.map(|v| v.value(&mut cx))
|
||||
.unwrap_or(false),
|
||||
minify_js: opt
|
||||
.get_opt::<JsBoolean, _, _>(&mut cx, "minify_js")?
|
||||
.map(|v| v.value(&mut cx))
|
||||
.unwrap_or(false),
|
||||
remove_bangs: opt
|
||||
.get_opt::<JsBoolean, _, _>(&mut cx, "remove_bangs")?
|
||||
.map(|v| v.value(&mut cx))
|
||||
.unwrap_or(false),
|
||||
remove_processing_instructions: opt
|
||||
.get_opt::<JsBoolean, _, _>(&mut cx, "remove_processing_instructions")?
|
||||
.map(|v| v.value(&mut cx))
|
||||
.unwrap_or(false),
|
||||
do_not_minify_doctype: get_bool!(cx, opt, "do_not_minify_doctype"),
|
||||
ensure_spec_compliant_unquoted_attribute_values: get_bool!(
|
||||
cx,
|
||||
opt,
|
||||
"ensure_spec_compliant_unquoted_attribute_values"
|
||||
),
|
||||
keep_closing_tags: get_bool!(cx, opt, "keep_closing_tags"),
|
||||
keep_html_and_head_opening_tags: get_bool!(cx, opt, "keep_html_and_head_opening_tags"),
|
||||
keep_spaces_between_attributes: get_bool!(cx, opt, "keep_spaces_between_attributes"),
|
||||
keep_comments: get_bool!(cx, opt, "keep_comments"),
|
||||
minify_css: get_bool!(cx, opt, "minify_css"),
|
||||
minify_css_level_1: get_bool!(cx, opt, "minify_css_level_1"),
|
||||
minify_css_level_2: get_bool!(cx, opt, "minify_css_level_2"),
|
||||
minify_css_level_3: get_bool!(cx, opt, "minify_css_level_3"),
|
||||
minify_js: get_bool!(cx, opt, "minify_js"),
|
||||
remove_bangs: get_bool!(cx, opt, "remove_bangs"),
|
||||
remove_processing_instructions: get_bool!(cx, opt, "remove_processing_instructions"),
|
||||
};
|
||||
let out = minify_html::minify(src.as_slice(&mut cx), &cfg);
|
||||
Ok(JsBuffer::external(&mut cx, out))
|
||||
|
|
|
@ -25,6 +25,9 @@ fn minify(
|
|||
keep_html_and_head_opening_tags: bool,
|
||||
keep_spaces_between_attributes: bool,
|
||||
minify_css: bool,
|
||||
minify_css_level_1: bool,
|
||||
minify_css_level_2: bool,
|
||||
minify_css_level_3: bool,
|
||||
minify_js: bool,
|
||||
remove_bangs: bool,
|
||||
remove_processing_instructions: bool,
|
||||
|
@ -40,6 +43,9 @@ fn minify(
|
|||
keep_html_and_head_opening_tags,
|
||||
keep_spaces_between_attributes,
|
||||
minify_css,
|
||||
minify_css_level_1,
|
||||
minify_css_level_2,
|
||||
minify_css_level_3,
|
||||
minify_js,
|
||||
remove_bangs,
|
||||
remove_processing_instructions,
|
||||
|
|
|
@ -36,6 +36,9 @@ methods! {
|
|||
keep_html_and_head_opening_tags: get_cfg_hash_prop!(cfg_hash, "keep_html_and_head_opening_tags"),
|
||||
keep_spaces_between_attributes: get_cfg_hash_prop!(cfg_hash, "keep_spaces_between_attributes"),
|
||||
minify_css: get_cfg_hash_prop!(cfg_hash, "minify_css"),
|
||||
minify_css_level_1: get_cfg_hash_prop!(cfg_hash, "minify_css_level_1"),
|
||||
minify_css_level_2: get_cfg_hash_prop!(cfg_hash, "minify_css_level_2"),
|
||||
minify_css_level_3: get_cfg_hash_prop!(cfg_hash, "minify_css_level_3"),
|
||||
minify_js: get_cfg_hash_prop!(cfg_hash, "minify_js"),
|
||||
remove_bangs: get_cfg_hash_prop!(cfg_hash, "remove_bangs"),
|
||||
remove_processing_instructions: get_cfg_hash_prop!(cfg_hash, "remove_processing_instructions"),
|
||||
|
|
|
@ -50,8 +50,8 @@ impl Eq for AttrVal {}
|
|||
|
||||
#[derive(Eq, PartialEq, Debug)]
|
||||
pub enum RcdataContentType {
|
||||
Textarea,
|
||||
Title,
|
||||
Textarea,
|
||||
Title,
|
||||
}
|
||||
|
||||
// Derive Eq for testing.
|
||||
|
|
|
@ -14,9 +14,15 @@ pub struct Cfg {
|
|||
pub keep_spaces_between_attributes: bool,
|
||||
/// Keep all comments.
|
||||
pub keep_comments: bool,
|
||||
/// If enabled, CSS in `<style>` tags and `style` attributes are minified.
|
||||
/// Minify CSS in `<style>` tags and `style` attributes using [https://github.com/Mnwa/css-minify](css-minify). By default, the optimisation level is 1 as specified by the CSS minifier, but this can be adjusted by the minify_css_level_* settings.
|
||||
pub minify_css: bool,
|
||||
/// If enabled, JavaScript in `<script>` tags are minified using
|
||||
/// Use optimisation level 1 for the CSS minifier. This is currently the default, but may change in the future if higher levels become safe.
|
||||
pub minify_css_level_1: bool,
|
||||
/// Use optimisation level 2 for the CSS minifier. This is mostly safe, but may perform some dangerous optimisations.
|
||||
pub minify_css_level_2: bool,
|
||||
/// Use optimisation level 3 for the CSS minifier. This performs many dangerous optimisations, so ensure any input works with this level.
|
||||
pub minify_css_level_3: bool,
|
||||
/// Minify JavaScript in `<script>` tags using
|
||||
/// [minify-js](https://github.com/wilsonzlin/minify-js).
|
||||
///
|
||||
/// Only `<script>` tags with a valid or no
|
||||
|
|
|
@ -6,7 +6,19 @@ use css_minify::optimizations::{Level, Minifier};
|
|||
|
||||
pub fn minify_css(cfg: &Cfg, out: &mut Vec<u8>, code: &[u8]) {
|
||||
if cfg.minify_css {
|
||||
let result = Minifier::default().minify(unsafe { from_utf8_unchecked(code) }, Level::Three);
|
||||
let result = Minifier::default().minify(
|
||||
unsafe { from_utf8_unchecked(code) },
|
||||
if cfg.minify_css_level_1 {
|
||||
Level::One
|
||||
} else if cfg.minify_css_level_2 {
|
||||
Level::Two
|
||||
} else if cfg.minify_css_level_3 {
|
||||
Level::Three
|
||||
} else {
|
||||
// Default to One, as other levels may perform dangerous optimisations.
|
||||
Level::One
|
||||
},
|
||||
);
|
||||
// TODO Collect error as warning.
|
||||
if let Ok(min) = result {
|
||||
if min.len() < code.len() {
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
use crate::{ast::RcdataContentType, tag::{TAG_TEXTAREA_END, TAG_TITLE_END}, entity::encode::encode_entities};
|
||||
use crate::{
|
||||
ast::RcdataContentType,
|
||||
entity::encode::encode_entities,
|
||||
tag::{TAG_TEXTAREA_END, TAG_TITLE_END},
|
||||
};
|
||||
|
||||
pub fn minify_rcdata(out: &mut Vec<u8>, typ: RcdataContentType, text: &[u8]) {
|
||||
// Encode entities, since they're still decoded by the browser.
|
||||
|
@ -6,12 +10,16 @@ pub fn minify_rcdata(out: &mut Vec<u8>, typ: RcdataContentType, text: &[u8]) {
|
|||
|
||||
// Since the text has been decoded, there may be unintentional matches to end tags that we must escape.
|
||||
let html = match typ {
|
||||
RcdataContentType::Textarea => &*TAG_TEXTAREA_END,
|
||||
RcdataContentType::Title => &*TAG_TITLE_END,
|
||||
}.replace_all_bytes(&html, &[match typ {
|
||||
RcdataContentType::Textarea => b"</textarea".as_slice(),
|
||||
RcdataContentType::Title => b"</title".as_slice(),
|
||||
}]);
|
||||
RcdataContentType::Textarea => &*TAG_TEXTAREA_END,
|
||||
RcdataContentType::Title => &*TAG_TITLE_END,
|
||||
}
|
||||
.replace_all_bytes(
|
||||
&html,
|
||||
&[match typ {
|
||||
RcdataContentType::Textarea => b"</textarea".as_slice(),
|
||||
RcdataContentType::Title => b"</title".as_slice(),
|
||||
}],
|
||||
);
|
||||
|
||||
out.extend_from_slice(&html);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue