terser / html-minifier-terser

actively maintained fork of html-minifier - minify HTML, CSS and JS code using terser - supports ES6 code
https://terser.org/html-minifier-terser
MIT License
376 stars 30 forks source link

Setting minify-css or minify-js to false does not work as expected #119

Closed wanjakarl closed 2 years ago

wanjakarl commented 2 years ago

I am using html-minifier-terser in my package.json with Node 16.

In the official documentation I found a help command. Running this gives me a list of options:

html-minifier-terser --help

I found two options that could serve my needs:

--minify-css [value]                 Minify CSS in style elements and style attributes (uses clean-css)
--minify-js [value]                  Minify Javascript in script elements and on* attributes (uses terser)

The type of [value] is not defined – but since the sample command at „Sample command line:” uses --minify-js true I assume that I can also use --minify-js false.

Sample command:

html-minifier-terser --collapse-whitespace --remove-comments --minify-js true

But whatever I do, using --minify-js false does not do the trick.

The commands that I run are:

html-minifier-terser --input-dir src --output-dir dist --minify-css true --minify-js true # input is the same as output. no minification happening.
html-minifier-terser --input-dir src --output-dir dist --collapse-whitespace --minify-css false --minify-js false # HTML, CSS and JavaScript is minified
html-minifier-terser --input-dir src --output-dir dist --collapse-whitespace # exactly same as above

I am using --collapse-whitespace since nothing happens when I don't.

I created a simple setup so it's easy to understand. In src you will find a single HTML, CSS and JavaScript file. When running the command for the minification, the results are in dist.

html-minifier-test.zip html-minifier-test_without-node_modules.zip

Based on my assumptions and the provided code, the evolving questions are:

Thank you very much for your time and responding!

Greetings from cologne!

DanielRuf commented 2 years ago

Hi @wanjapflueger,

please see the note there:

https://github.com/terser/html-minifier-terser#usage

Note that almost all options are disabled by default. Experiment and find what works best for you and your project.

DanielRuf commented 2 years ago

You can see some enabled settings in the demo at https://terser.org/html-minifier-terser/

wanjakarl commented 2 years ago

Hi @DanielRuf ,

thank you for your quick reply!

Since --minify-css [value] is in the „list of available options”, I assume it is enabled and I can set it to true or false. Or am I wrong?

In case the options --minify-css and --minify-js are disabled by default – how can I enable them when using the command line?

The documentation tells me to „experiment and find what works best” – but that is what I did (as stated in the issue above) and nothing worked at all.

Simplified from https://github.com/terser/html-minifier-terser/issues/119#issue-1174658448:

# I want to minify .html, .css and .js files in my directory → but nothing is happening
html-minifier-terser --minify-css true --minify-js true

# I want to minify .html files only but not .css and not .js files → but all files are being minified
html-minifier-terser --minify-css false --minify-js false --collapse-whitespace

# I do not specify what I want to be minified → all files are being minified
html-minifier-terser --collapse-whitespace

Thanks again!

DanielRuf commented 2 years ago

I can not really follow. When you disable css and js minification, then only html minification is done. And for my case it works:

Both options disabled html-minifier-terser --input-dir src --output-dir dist --collapse-whitespace --minify-css false --minify-js false

--- src/test.html   2022-03-23 13:44:53.950067915 +0100
+++ dist/test.html  2022-03-23 13:45:00.614017595 +0100
@@ -1,25 +1,9 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
-    <meta charset="UTF-8">
-    <meta http-equiv="X-UA-Compatible" content="IE=edge">
-    <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <title>Document</title>
-</head>
-<body>
-    <style>
-        .some-empty-selector {}
+<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Document</title></head><body><style>.some-empty-selector {}
         .some-selector {
             width: 0px;
             height: 0px;
-        }
-    </style>
-    <script>
-        console.log(true); console.log(
+        }</style><script>console.log(true); console.log(
             1,
             2,
             3
-        );
-    </script>
-</body>
-</html>
\ Kein Zeilenumbruch am Dateiende.
+        );</script></body></html>
\ Kein Zeilenumbruch am Dateiende.

Both options enabled html-minifier-terser --input-dir src --output-dir dist --collapse-whitespace --minify-css true --minify-js true

--- src/test.html   2022-03-23 13:44:53.950067915 +0100
+++ dist/test.html  2022-03-23 13:53:44.014065391 +0100
@@ -1,25 +1 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
-    <meta charset="UTF-8">
-    <meta http-equiv="X-UA-Compatible" content="IE=edge">
-    <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <title>Document</title>
-</head>
-<body>
-    <style>
-        .some-empty-selector {}
-        .some-selector {
-            width: 0px;
-            height: 0px;
-        }
-    </style>
-    <script>
-        console.log(true); console.log(
-            1,
-            2,
-            3
-        );
-    </script>
-</body>
-</html>
\ Kein Zeilenumbruch am Dateiende.
+<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Document</title></head><body><style>.some-selector{width:0;height:0}</style><script>console.log(!0),console.log(1,2,3)</script></body></html>
\ Kein Zeilenumbruch am Dateiende.

Used test file:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <style>
        .some-empty-selector {}
        .some-selector {
            width: 0px;
            height: 0px;
        }
    </style>
    <script>
        console.log(true); console.log(
            1,
            2,
            3
        );
    </script>
</body>
</html>
DanielRuf commented 2 years ago

Your example commands use stdin and stdout. So this is probably not what you want to use.

See also https://github.com/terser/html-minifier-terser/blob/master/cli.js#L293-L307

DanielRuf commented 2 years ago

This works for me without any issues:

html-minifier-terser --input-dir src --output-dir dist --collapse-whitespace --minify-css false --minify-js false

result:

--- src/test.html   2022-03-23 13:44:53.950067915 +0100
+++ dist/test.html  2022-03-23 14:01:03.346747980 +0100
@@ -1,25 +1,9 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
-    <meta charset="UTF-8">
-    <meta http-equiv="X-UA-Compatible" content="IE=edge">
-    <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <title>Document</title>
-</head>
-<body>
-    <style>
-        .some-empty-selector {}
+<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Document</title></head><body><style>.some-empty-selector {}
         .some-selector {
             width: 0px;
             height: 0px;
-        }
-    </style>
-    <script>
-        console.log(true); console.log(
+        }</style><script>console.log(true); console.log(
             1,
             2,
             3
-        );
-    </script>
-</body>
-</html>
\ Kein Zeilenumbruch am Dateiende.
+        );</script></body></html>
\ Kein Zeilenumbruch am Dateiende.

Same for this: html-minifier-terser --input-dir src --output-dir dist --collapse-whitespace

--- src/test.html   2022-03-23 13:44:53.950067915 +0100
+++ dist/test.html  2022-03-23 14:02:31.502082317 +0100
@@ -1,25 +1,9 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
-    <meta charset="UTF-8">
-    <meta http-equiv="X-UA-Compatible" content="IE=edge">
-    <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <title>Document</title>
-</head>
-<body>
-    <style>
-        .some-empty-selector {}
+<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Document</title></head><body><style>.some-empty-selector {}
         .some-selector {
             width: 0px;
             height: 0px;
-        }
-    </style>
-    <script>
-        console.log(true); console.log(
+        }</style><script>console.log(true); console.log(
             1,
             2,
             3
-        );
-    </script>
-</body>
-</html>
\ Kein Zeilenumbruch am Dateiende.
+        );</script></body></html>
\ Kein Zeilenumbruch am Dateiende.

To apply the changes only to specific filetypes, please take a look at this:

--file-ext Specify an extension to be read, ex: html

DanielRuf commented 2 years ago

I want to minify .html, .css and .js files in my directory → but nothing is happening html-minifier-terser --minify-css true --minify-js true

works for me when I apply it to my testfile, please keep in mind that it only parses and compresses html files and files where <style> tags are found

See also: https://github.com/terser/html-minifier-terser/blob/master/src/htmlminifier.js#L282-L290 https://github.com/terser/html-minifier-terser/blob/master/src/htmlminifier.js#L320-L323 https://github.com/terser/html-minifier-terser/blob/master/src/htmlminifier.js#L1210-L1212

I want to minify .html files only but not .css and not .js files → but all files are being minified html-minifier-terser --minify-css false --minify-js false --collapse-whitespace

see the --file-ext option, please also take a look at cli.js

I do not specify what I want to be minified → all files are being minified html-minifier-terser --collapse-whitespace

that is the correct default behavior as html-minifier itself removes all these whitespaces (this option comes from html-minifier, not cleancss and others): https://github.com/terser/html-minifier-terser/blob/master/cli.js#L299 https://github.com/terser/html-minifier-terser/blob/master/cli.js#L259 https://github.com/terser/html-minifier-terser/blob/master/cli.js#L192

html-minifier-terser is meant to be run right after compilation as last step (like html-webpack-plugin works (they use html-minifier-terser)

So final conclusion by me: works like it should. Please compile your application and then run html-minifier-terser on the resulting html file. Please compare the result of a single html file with js and css included and run css and js minifier on it. You will see that then the css code gets the proper minified code (trailing semicolon removed and so on).

DanielRuf commented 2 years ago

Closing as everything works as expected. When css and js minification are disabled, the html-minifier only does the relevant changes and does not understand or parse js and css code in such cases.

wanjakarl commented 2 years ago

Hello @DanielRuf ,

thank you for your explanations!

I conclude:

--minify-css true|false and --minify-js true|false only apply to JavaScript in HTMLScriptElements (<script>) and CSS in HTMLStyleElements (<style>). As you point out in the comments above this works as expected.

However I was trying to minify only files with the extension 'html' (like index.html) in a directory containing with multiple file types like HTML, CSS and JavaScript files.

--minify-css true|false and --minify-js true|false does not affect JavaScript and CSS files. They will be minified regardless of the value (true|false).

--file-ext does that trick for me:

# minify only HTML files
html-minifier-terser --input-dir src --output-dir dist --collapse-whitespace --file-ext html

(as you pointed out in https://github.com/terser/html-minifier-terser/issues/119#issuecomment-1076351458 at „To apply the changes only to specific filetypes”)

🙏 @DanielRuf please consider documenting --file-ext [extension] in README.md. Much appreciated!

PS: You could also just paste the output of html-minifier-terser --help to the README.md.

Output of html-minifier-terser --help from 7.0.0-alpha.2 on 2022-03-28:

> html-minifier-terser --help

Usage: html-minifier-terser [options] [files...]

Options:
  -V, --version                        output the version number
  --case-sensitive                     Treat attributes in case sensitive
                                       manner (useful for SVG; e.g. viewBox)
  --collapse-boolean-attributes        Omit attribute values from boolean
                                       attributes
  --collapse-inline-tag-whitespace     Collapse white space around inline tag
  --collapse-whitespace                Collapse white space that contributes to
                                       text nodes in a document tree.
  --conservative-collapse              Always collapse to 1 space (never remove
                                       it entirely)
  --continue-on-parse-error            Handle parse errors instead of aborting
  --custom-attr-assign <value>         Arrays of regex'es that allow to support
                                       custom attribute assign expressions
                                       (e.g. '<div flex?="{{mode !=
                                       cover}}"></div>')
  --custom-attr-collapse <value>       Regex that specifies custom attribute to
                                       strip newlines from (e.g. /ng-class/)
  --custom-attr-surround <value>       Arrays of regex'es that allow to support
                                       custom attribute surround expressions
                                       (e.g. <input {{#if
                                       value}}checked="checked"{{/if}}>)
  --custom-event-attributes <value>    Arrays of regex'es that allow to support
                                       custom event attributes for minifyJS
                                       (e.g. ng-click)
  --decode-entities                    Use direct Unicode characters whenever
                                       possible
  --no-html5                           Parse input according to HTML5
                                       specifications
  --ignore-custom-comments <value>     Array of regex'es that allow to ignore
                                       certain comments, when matched
  --ignore-custom-fragments <value>    Array of regex'es that allow to ignore
                                       certain fragments, when matched (e.g.
                                       <?php ... ?>, {{ ... }})
  --no-include-auto-generated-tags     Insert tags generated by HTML parser
  --keep-closing-slash                 Keep the trailing slash on singleton
                                       elements
  --max-line-length <value>            Max line length
  --minify-css [value]                 Minify CSS in style elements and style
                                       attributes (uses clean-css)
  --minify-js [value]                  Minify Javascript in script elements and
                                       on* attributes (uses terser)
  --minify-urls [value]                Minify URLs in various attributes (uses
                                       relateurl)
  --no-newlines-before-tag-close       Never add a newline before a tag that
                                       closes an element
  --preserve-line-breaks               Always collapse to 1 line break (never
                                       remove it entirely) when whitespace
                                       between tags include a line break.
  --prevent-attributes-escaping        Prevents the escaping of the values of
                                       attributes.
  --process-conditional-comments       Process contents of conditional comments
                                       through minifier
  --process-scripts <value>            Array of strings corresponding to types
                                       of script elements to process through
                                       minifier (e.g. "text/ng-template",
                                       "text/x-handlebars-template", etc.)
  --quote-character <value>            Type of quote to use for attribute
                                       values (' or ")
  --remove-attribute-quotes            Remove quotes around attributes when
                                       possible.
  --remove-comments                    Strip HTML comments
  --remove-empty-attributes            Remove all attributes with
                                       whitespace-only values
  --remove-empty-elements              Remove all elements with empty contents
  --remove-optional-tags               Remove unrequired tags
  --remove-redundant-attributes        Remove attributes when value matches
                                       default.
  --remove-script-type-attributes      Removes the following attributes from
                                       script tags: text/javascript,
                                       text/ecmascript, text/jscript,
                                       application/javascript,
                                       application/x-javascript,
                                       application/ecmascript. Other type
                                       attribute values are left intact
  --remove-style-link-type-attributes  Remove type="text/css" from style and
                                       link tags. Other type attribute values
                                       are left intact.
  --remove-tag-whitespace              Remove space between attributes whenever
                                       possible
  --sort-attributes                    Sort attributes by frequency
  --sort-class-name                    Sort style classes by frequency
  --trim-custom-fragments              Trim white space around
                                       ignoreCustomFragments.
  --use-short-doctype                  Replaces the doctype with the short
                                       (HTML5) doctype
  -o --output <file>                   Specify output file (if not specified
                                       STDOUT will be used for output)
  -c --config-file <file>              Use config file
  --input-dir <dir>                    Specify an input directory
  --output-dir <dir>                   Specify an output directory
  --file-ext <text>                    Specify an extension to be read, ex:
                                       html
  -h, --help                           display help for command
DanielRuf commented 2 years ago

🙏 @DanielRuf please consider documenting --file-ext [extension] in README.md. Much appreciated!

PS: You could also just paste the output of html-minifier-terser --help to the README.md.

The documentation currently only lists options for the JS API, not the CLI. Normally when you work with a CLI you use manpage / man or append --help.

For the CLI we would need a separate section in the readme. PRs which add such a section are very welcome.