diff --git a/plugins/postcss-minify/CHANGELOG.md b/plugins/postcss-minify/CHANGELOG.md index 6c926f779..9ea842bb7 100644 --- a/plugins/postcss-minify/CHANGELOG.md +++ b/plugins/postcss-minify/CHANGELOG.md @@ -1,5 +1,9 @@ # Changes to PostCSS Minify +### Unreleased (minor) + +- Preserve important comments (e.g. `/*! something important */`) + ### 1.0.3 _December 15, 2023_ diff --git a/plugins/postcss-minify/README.md b/plugins/postcss-minify/README.md index a936c56ec..9de8f7c4f 100644 --- a/plugins/postcss-minify/README.md +++ b/plugins/postcss-minify/README.md @@ -28,6 +28,8 @@ Compared to other minifiers, [PostCSS Minify] is purely focused on correctness a * legal text is preserved */ +/*! an important comment */ + :root { --mainColor: #12345678; } @@ -63,7 +65,7 @@ becomes : *//* * Copyright: CSSTools Authors * legal text is preserved - */:root{--mainColor: #12345678;}body{color:var(--mainColor);font-family:system-ui}a{color:rgb(0 0 100% / 90%);&:hover{color:rebeccapurple}> span{color:color-mix(in oklch, cyan, green 25%)}}:is(input, button):is(:hover, :focus){color:oklch(40% 0.268735435 34.568626)} + *//*! an important comment */:root{--mainColor: #12345678;}body{color:var(--mainColor);font-family:system-ui}a{color:rgb(0 0 100% / 90%);&:hover{color:rebeccapurple}> span{color:color-mix(in oklch, cyan, green 25%)}}:is(input, button):is(:hover, :focus){color:oklch(40% 0.268735435 34.568626)} ``` ## Usage diff --git a/plugins/postcss-minify/dist/index.cjs b/plugins/postcss-minify/dist/index.cjs index 8c50074a6..e637038bc 100644 --- a/plugins/postcss-minify/dist/index.cjs +++ b/plugins/postcss-minify/dist/index.cjs @@ -1 +1 @@ -"use strict";var e=require("@csstools/css-tokenizer");const t=/(?:license|copyright)/i,r=/sourceMappingURL/i,s=/(?:\s|\/\*)/,o=/^layer$/i;function minify(t,r){if(!r)return r;if(t.has(r))return t.get(r);const o=r.trim();if(""===o)return t.set(r,""),"";if(!s.test(o))return t.set(r,o),o;const n=e.tokenize({css:o});let i,a=!1;for(let t=0;t{const e=new Map;return{postcssPlugin:"postcss-minify",OnceExit(s){s.raws.before="",s.raws.after="\n",s.walk((s=>{switch(s.type){case"atrule":if(removeEmptyNodes(s))return;return s.raws.after="",s.raws.afterName=" ",s.raws.before="",s.raws.between="",s.raws.params=void 0,setSemicolon(s),void(s.params=minify(e,s.params));case"rule":if(removeEmptyNodes(s))return;return s.raws.after="",s.raws.before="",s.raws.between="",s.raws.selector=void 0,setSemicolon(s),void(s.selector=minify(e,s.selector));case"decl":return s.prop.startsWith("--")?void(s.raws.before=""):(s.raws.before="",s.raws.between=":",s.raws.important=s.important?"!important":"",s.raws.value=void 0,void(s.value=minify(e,s.value)));case"comment":return t.test(s.text)||r.test(s.text)?void(s.raws.before=""):void s.remove()}}))}}};creator.postcss=!0,module.exports=creator; +"use strict";var e=require("@csstools/css-tokenizer");const t=/(?:license|copyright)/i,r=/sourceMappingURL/i,s=/(?:\s|\/\*)/,o=/^layer$/i;function minify(t,r){if(!r)return r;if(t.has(r))return t.get(r);const o=r.trim();if(""===o)return t.set(r,""),"";if(!s.test(o))return t.set(r,o),o;const n=e.tokenize({css:o});let i,a=!1;for(let t=0;t{const e=new Map;return{postcssPlugin:"postcss-minify",OnceExit(s){s.raws.before="",s.raws.after="\n",s.walk((s=>{switch(s.type){case"atrule":if(removeEmptyNodes(s))return;return s.raws.after="",s.raws.afterName=" ",s.raws.before="",s.raws.between="",s.raws.params=void 0,setSemicolon(s),void(s.params=minify(e,s.params));case"rule":if(removeEmptyNodes(s))return;return s.raws.after="",s.raws.before="",s.raws.between="",s.raws.selector=void 0,setSemicolon(s),void(s.selector=minify(e,s.selector));case"decl":return s.prop.startsWith("--")?void(s.raws.before=""):(s.raws.before="",s.raws.between=":",s.raws.important=s.important?"!important":"",s.raws.value=void 0,void(s.value=minify(e,s.value)));case"comment":return s.text.startsWith("!")||t.test(s.text)||r.test(s.text)?void(s.raws.before=""):void s.remove()}}))}}};creator.postcss=!0,module.exports=creator; diff --git a/plugins/postcss-minify/dist/index.mjs b/plugins/postcss-minify/dist/index.mjs index 77e2af622..fe3816869 100644 --- a/plugins/postcss-minify/dist/index.mjs +++ b/plugins/postcss-minify/dist/index.mjs @@ -1 +1 @@ -import{tokenize as e,TokenType as t}from"@csstools/css-tokenizer";const r=/(?:license|copyright)/i,s=/sourceMappingURL/i,o=/(?:\s|\/\*)/,n=/^layer$/i;function minify(r,s){if(!s)return s;if(r.has(s))return r.get(s);const n=s.trim();if(""===n)return r.set(s,""),"";if(!o.test(n))return r.set(s,n),n;const a=e({css:n});let i,c=!1;for(let e=0;e{const e=new Map;return{postcssPlugin:"postcss-minify",OnceExit(t){t.raws.before="",t.raws.after="\n",t.walk((t=>{switch(t.type){case"atrule":if(removeEmptyNodes(t))return;return t.raws.after="",t.raws.afterName=" ",t.raws.before="",t.raws.between="",t.raws.params=void 0,setSemicolon(t),void(t.params=minify(e,t.params));case"rule":if(removeEmptyNodes(t))return;return t.raws.after="",t.raws.before="",t.raws.between="",t.raws.selector=void 0,setSemicolon(t),void(t.selector=minify(e,t.selector));case"decl":return t.prop.startsWith("--")?void(t.raws.before=""):(t.raws.before="",t.raws.between=":",t.raws.important=t.important?"!important":"",t.raws.value=void 0,void(t.value=minify(e,t.value)));case"comment":return r.test(t.text)||s.test(t.text)?void(t.raws.before=""):void t.remove()}}))}}};creator.postcss=!0;export{creator as default}; +import{tokenize as e,TokenType as t}from"@csstools/css-tokenizer";const r=/(?:license|copyright)/i,s=/sourceMappingURL/i,o=/(?:\s|\/\*)/,n=/^layer$/i;function minify(r,s){if(!s)return s;if(r.has(s))return r.get(s);const n=s.trim();if(""===n)return r.set(s,""),"";if(!o.test(n))return r.set(s,n),n;const a=e({css:n});let i,c=!1;for(let e=0;e{const e=new Map;return{postcssPlugin:"postcss-minify",OnceExit(t){t.raws.before="",t.raws.after="\n",t.walk((t=>{switch(t.type){case"atrule":if(removeEmptyNodes(t))return;return t.raws.after="",t.raws.afterName=" ",t.raws.before="",t.raws.between="",t.raws.params=void 0,setSemicolon(t),void(t.params=minify(e,t.params));case"rule":if(removeEmptyNodes(t))return;return t.raws.after="",t.raws.before="",t.raws.between="",t.raws.selector=void 0,setSemicolon(t),void(t.selector=minify(e,t.selector));case"decl":return t.prop.startsWith("--")?void(t.raws.before=""):(t.raws.before="",t.raws.between=":",t.raws.important=t.important?"!important":"",t.raws.value=void 0,void(t.value=minify(e,t.value)));case"comment":return t.text.startsWith("!")||r.test(t.text)||s.test(t.text)?void(t.raws.before=""):void t.remove()}}))}}};creator.postcss=!0;export{creator as default}; diff --git a/plugins/postcss-minify/src/index.ts b/plugins/postcss-minify/src/index.ts index ea3ee0843..769f6e043 100644 --- a/plugins/postcss-minify/src/index.ts +++ b/plugins/postcss-minify/src/index.ts @@ -168,7 +168,14 @@ const creator: PluginCreator = () => { case 'comment': - if (HAS_LEGAL_KEYWORDS.test(node.text) || HAS_SOURCE_MAP.test(node.text)) { + if ( + // `/*! ... */` is a common pattern to indicate that a comment is important and should not be removed. + node.text.startsWith('!') || + // Comments containing the words `license` or `copyright` should not be removed. + HAS_LEGAL_KEYWORDS.test(node.text) || + // Comments containing the word `sourceMappingURL` should not be removed. + HAS_SOURCE_MAP.test(node.text) + ) { node.raws.before = ''; return; } diff --git a/plugins/postcss-minify/test/examples/example.css b/plugins/postcss-minify/test/examples/example.css index bab6dcc3b..e59684d38 100644 --- a/plugins/postcss-minify/test/examples/example.css +++ b/plugins/postcss-minify/test/examples/example.css @@ -8,6 +8,8 @@ * legal text is preserved */ +/*! an important comment */ + :root { --mainColor: #12345678; } diff --git a/plugins/postcss-minify/test/examples/example.expect.css b/plugins/postcss-minify/test/examples/example.expect.css index f7a2b1a2c..38634e60e 100644 --- a/plugins/postcss-minify/test/examples/example.expect.css +++ b/plugins/postcss-minify/test/examples/example.expect.css @@ -4,4 +4,4 @@ *//* * Copyright: CSSTools Authors * legal text is preserved - */:root{--mainColor: #12345678;}body{color:var(--mainColor);font-family:system-ui}a{color:rgb(0 0 100% / 90%);&:hover{color:rebeccapurple}> span{color:color-mix(in oklch, cyan, green 25%)}}:is(input, button):is(:hover, :focus){color:oklch(40% 0.268735435 34.568626)} + *//*! an important comment */:root{--mainColor: #12345678;}body{color:var(--mainColor);font-family:system-ui}a{color:rgb(0 0 100% / 90%);&:hover{color:rebeccapurple}> span{color:color-mix(in oklch, cyan, green 25%)}}:is(input, button):is(:hover, :focus){color:oklch(40% 0.268735435 34.568626)}