Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Minify JavaScript" / UglifyJS fails without reporting error #967

Closed
gnbl opened this issue Sep 25, 2018 · 10 comments
Closed

"Minify JavaScript" / UglifyJS fails without reporting error #967

gnbl opened this issue Sep 25, 2018 · 10 comments

Comments

@gnbl
Copy link

gnbl commented Sep 25, 2018

I'm running html-minifier 3.5.14 locally but also tried the current online version http://kangax.github.io/html-minifier/ with my code, which just does not seem to minify the javascript.
I've narrowed down the cause to a const declaration:

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>title</title>
  <style>
    html,
    body {
      margin: 0;
      padding: 0;
    }
  </style>
  <script>
    document.addEventListener("DOMContentLoaded", function() {
      
      const fail = [{n:"object"},];

    }); //
  </script>
</head>

<body>
Hello world!
</body>

</html>

results in

<!doctype html><html lang=en><meta charset=UTF-8><title>title</title><style>body,html{margin:0;padding:0}</style><script>document.addEventListener("DOMContentLoaded", function() {
      
      const fail = [{n:"object"},];

    }); //</script>Hello world!

It works when I change it to a plain old var.

There's a note on SO:
https://stackoverflow.com/a/47440295

UglifyJS does not support es6. const is an es6 declaration, so it throws an error.
What is weird is that the package you use does not transpile its files to es5 to be used anywhere.
If you want to still use UglifyJS (to re-use the configuration for example) use the ES6+ compatible version, uglify-es.

However, I don't get an error with my local html-minfier either.

It would be nice if the user would get to see the underlying error message.


It also can't handle default function parameters, `let`, `=>`, etc. . There's a demo at http://lisperator.net/uglifyjs/ which throws errors.
@gnbl gnbl changed the title "Minify JavaScript" / UglifyJS fails on "const" without reporting error "Minify JavaScript" / UglifyJS fails without reporting error Sep 25, 2018
@kzc
Copy link

kzc commented Oct 2, 2018

html-minifier uses uglify-js which only supports ES5.

const and let are ES6 contructs.

#843 (comment)

@gnbl
Copy link
Author

gnbl commented Oct 3, 2018

Right, as cited above. The emphasis should be on "fails without error". Or rather "ignores error" without user message.

@kzc
Copy link

kzc commented Oct 3, 2018

It's working as designed. If it cannot parse the JS it will emit it as is.

@joshribakoff
Copy link

It's working as designed. If it cannot parse the JS it will emit it as is.

Right, again, that was acknowledged in the original issue report:

It would be nice if the user would get to see the underlying error message.

Silently failing instead of having an error or warning is egregious. I'd like to know what the use case is for a tool to silently fail when passed unsupported input?

Precisely we are petitioning for the design to change which would make the tool more reliable & save downstream users lots of wasted time & woes. Is there an actual objection to changing the design? It doesn't seem to make much sense to expend time debating whether this is a feature request vs a bug, if that's your intention, we're just expressing our opinion that the current behavior is not very useful & that changing the behavior would be more useful to us.

People will end up with seemingly random unminified output with no idea why, spend lots of time hunting down why, then will end up here & expend your time posting issues.... If the tool outputted a warning then at least users would be cognizant of the implications of adding es6, and would be able to make a deliberate decision to either not use es6 / disable minification intentionally.

I would like to know if you are objecting to making a change here, and the reason why? Simply replying with facts that were already stated in the original issue report are not particularly helpful. I think it would be more helpful to outright say that you're not supporting the use case (and if so why), or acknowledge that the current workflow can be improved so that someone can start on a PR? Instead it seems to me like we may be spinning our wheels here without any resolution one way or the other, and I have to wonder to what end.

This is a great tool & I while I cannot speak for others, I feel the intention of the community is to make it even greater, not debate semantics.

@lhorvati
Copy link

Is it possible for html-minifier to use uglifyes instead uglify-js?
uglifyes is the same but supports ES6
https://www.npmjs.com/package/gulp-uglifyes

@danielvaijk
Copy link

Actually, you could just use 'terser', which

is a fork of uglify-es that retains API and CLI compatibility with uglify-es and uglify-js@3.

The uglify-es package is no longer being maintained.
https://www.npmjs.com/package/terser

@natasha-ntsh
Copy link

@danielvaijk How exactly can we use terser with html-minifier?

@danielvaijk
Copy link

@janusz-bb, here's a snippet of a module I wrote for one of my projects. The code belongs to a helper function that minifies HTML content (via html-minifier) rendered by Pug on a server application using Express.

const html = await new Promise((resolve, reject) => {
    res.render(page.name, page.data, (err, html) => {
        err ? reject(err) : resolve(minify(html, {
            collapseBooleanAttributes   : true,
            collapseInlineTagWhitespace : true,
            collapseWhitespace          : true,
            minifyCSS                   : true,
            minifyJS                    : (text, inline) => { return terser.minify(text).code; },
        //  minifyURLs                  :
            removeAttributeQuotes       : true,
            removeComments              : true,
            removeEmptyAttributes       : true
        }));
    });
});

Notice how I plug in Terser in the minifyJS field of the minify method. That's how I use Terser with html-minifier. :)

@gnbl
Copy link
Author

gnbl commented Mar 1, 2020

This project appears to be unmaintained now, but a fork has moved to terser as pointed out in #1040

@andymel123
Copy link

andymel123 commented Aug 20, 2022

I have not tried html-minifier-terser yet because I just learned about it thanks to the post by @gnbl above, but I leave this note here for people having the same nasty problem (html-minifier not reporting uglify-js errors). I have extended @danielvaijk tip to wrap uglify-js in some code to recognize any problems with the to-be-minified code

function minifyWithHtmlMinifier(orig: string):string {
    
    return htmlMinifier.minify(orig, {

        // I have replaced the default minifyJS usage of the html-minifier
        // as this silently ignores any uglifyjs errors and just displays
        // the non-minified code. Has cost me half a day to figure out
        // that it was not a configuration problem  but problem with the 
        // to-be-minified-code.
        // By setting the call to uglifyjs myself I can catch the errors and
        // rethrow them, failing fast, as this is much better than recognizing
        // a not-minified code much later when I don't remember what I changed
        minifyJS: (text, _inline) => { 

            const minifyResult = uglifyjs.minify(text, {
                compress: {
                    drop_console: true  // remove all console log entries
                }
            });

            if(minifyResult.warnings != null) {
                minifyResult.warnings.forEach(logger.warn);
            }
            if(minifyResult.error) {
                // TODO use terser if I need newer js features. I think terser supports
                // newer ES versions than uglifyjs
                throw new Error(`Can't minify the iframe template!`, {cause:minifyResult.error});
            } 
            
            return minifyResult.code;
            
        },
        minifyCSS: true,
        ignoreCustomFragments: [/{{.*}}/g],
        collapseBooleanAttributes: true,
        collapseInlineTagWhitespace: true,
        collapseWhitespace: true
    });
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants