grunt-usemin icon indicating copy to clipboard operation
grunt-usemin copied to clipboard

collapseWhitespace in htmlmin task makes usemin destroy the html

Open sindresorhus opened this issue 12 years ago • 13 comments

collapseWhitespace: true in the grunt-contrib-htmlmin makes usemin destroy most of the html.

The resulting index.html from generator-webapp becomes:


<script src="scripts/vendor/modernizr.js"></script>
            <p class="chromeframe">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> or <a href="http://www.google.com/chromeframe/?redirect=true">activate Google Chrome Frame</a> to improve your experience.</p>
        <![endif]--><!-- Google Analytics: change UA-XXXXX-X to be your site's ID. --><script>var _gaq=[['_setAccount','UA-XXXXX-X'],['_trackPageview']];
            (function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];
            g.src=('https:'==location.protocol?'//ssl':'//www')+'.google-analytics.com/ga.js';
            <script src="scripts/plugins.js"></script>

sindresorhus avatar Feb 11 '13 17:02 sindresorhus

Well, now it's compact ;) Is there a way to have a view on the output from htmlmin (i.e. the output html) ?

sleeper avatar Feb 11 '13 17:02 sleeper

Output form htmlmin:

<!DOCTYPE html>
<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html class=no-js> <!--<![endif]-->
    <head>
        <meta charset=utf-8>
        <meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1">
        <title></title>
        <meta name=description content="">
        <meta name=viewport content="width=device-width">
        <!-- Place favicon.ico and apple-touch-icon.png in the root directory -->
        <link rel=stylesheet href="styles/main.css">
        <!-- build:js scripts/vendor/modernizr.js -->
        <script src="components/modernizr/modernizr.js"></script>
        <!-- endbuild -->

    <body>
        <div class=container style=margin-top:50px>
            <div class=hero-unit>
                <h1>'Allo, 'Allo!</h1>
                <p>You now have</p>
                <ul>
                    <li>HTML5 Boilerplate</li>
                    <li>Twitter Bootstrap</li>
                    <li>RequireJS</li>
                </ul>
                <p>installed.</p>
                <h3>Enjoy coding! - Yeoman</h3>
            </div>
        </div>

        <!--[if lt IE 7]>
            <p class="chromeframe">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> or <a href="http://www.google.com/chromeframe/?redirect=true">activate Google Chrome Frame</a> to improve your experience.</p>
        <![endif]-->

        <!-- Google Analytics: change UA-XXXXX-X to be your site's ID. -->
        <script>
            var _gaq=[['_setAccount','UA-XXXXX-X'],['_trackPageview']];
            (function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];
            g.src=('https:'==location.protocol?'//ssl':'//www')+'.google-analytics.com/ga.js';
            s.parentNode.insertBefore(g,s)}(document,'script'));
        </script>

        <!-- build:js scripts/plugins.js -->
        <script src="components/sass-bootstrap/js/bootstrap-affix.js"></script>
        <script src="components/sass-bootstrap/js/bootstrap-alert.js"></script>
        <script src="components/sass-bootstrap/js/bootstrap-dropdown.js"></script>
        <script src="components/sass-bootstrap/js/bootstrap-tooltip.js"></script>
        <script src="components/sass-bootstrap/js/bootstrap-modal.js"></script>
        <script src="components/sass-bootstrap/js/bootstrap-transition.js"></script>
        <script src="components/sass-bootstrap/js/bootstrap-button.js"></script>
        <script src="components/sass-bootstrap/js/bootstrap-popover.js"></script>
        <script src="components/sass-bootstrap/js/bootstrap-typeahead.js"></script>
        <script src="components/sass-bootstrap/js/bootstrap-carousel.js"></script>
        <script src="components/sass-bootstrap/js/bootstrap-scrollspy.js"></script>
        <script src="components/sass-bootstrap/js/bootstrap-collapse.js"></script>
        <script src="components/sass-bootstrap/js/bootstrap-tab.js"></script>
        <!-- endbuild -->

        <!-- build:js scripts/amd-app.js -->
        <script data-main="scripts/main" src="components/requirejs/require.js"></script>
        <!-- endbuild -->


sindresorhus avatar Feb 11 '13 17:02 sindresorhus

Would love for this to be fixed. :)

btford avatar Feb 25 '13 04:02 btford

The same problem — usemin does not work after the htmlmin, it just ruins all my HTML code completely. So, usemin understands this:

<!-- build:js js/scripts.js -->
    <script src="js/common.js"></script>
    <script src="js/main.js"></script>
<!-- endbuild -->

but not this (after htmlmin processing — same as above, just compressed in one line):

<!-- build:js js/scripts.js --><script src="js/common.js"></script><script src="js/main.js"></script><!-- endbuild -->

artuska avatar Apr 15 '13 22:04 artuska

I did some kind of a workaround by splitting htmlmin into two targets. the first will do all the magic except collapseWhitespace to destination 'dist'. the second will override the html in 'dist'.

    htmlmin: {
      dist: {
        options: {
          removeComments: true,
          // removeCommentsFromCDATA: true,
          // removeCDATASectionsFromCDATA: true,
          // https://github.com/yeoman/grunt-usemin/issues/44
          // collapseWhitespace: true,
          collapseBooleanAttributes: true,
          removeAttributeQuotes: true,
          removeRedundantAttributes: true,
          // useShortDoctype: true,
          removeEmptyAttributes: true,
          // removeOptionalTags: true,
          // removeEmptyElements: true,
        },
        files: [{
          expand: true,
          cwd: '<%= yeoman.app %>',
          src: '{,*/}*.html',
          dest: '<%= yeoman.dist %>'
        }]
      },
      deploy: {
        options: {
          collapseWhitespace: true
        },
        files: [{
          expand: true,
          cwd: '<%= yeoman.dist %>',
          src: '{,*/}*.html',
          dest: '<%= yeoman.dist %>'
        }]
      }
    }

register your build task like

  grunt.registerTask('build', [
    // put all the other tasks you want to use before htmlmin and usemin
    'htmlmin:dist',
    'usemin',
    'htmlmin:deploy'
  ]);

i've used grunt-rev too and it worked well for me ;)

hope this helps.

iham avatar May 04 '13 09:05 iham

Why not just run all of htmlmin last? It's safest to do any sort of regex manipulation with a well formed document, so it seems like a better idea to perform manipulations and then minify.

I've been running it this way with no issues.

robwierzbowski avatar May 16 '13 17:05 robwierzbowski

@robwierzbowski Did you try and see it working your way?

AdrienGiboire avatar Jun 06 '13 14:06 AdrienGiboire

Yep, that's how it's being run in generator-jekyllrb: https://github.com/robwierzbowski/generator-jekyllrb/blob/37223004b8af22bf4f90430d39f74f603c4b22c4/app/templates/Gruntfile.js#L462-L477

robwierzbowski avatar Jun 06 '13 14:06 robwierzbowski

Running htmlmin last as @robwierzbowski suggests works for me.

rzschech avatar Jun 10 '13 13:06 rzschech

Thanks, @iham, your solution works great!

mgol avatar Jun 25 '13 12:06 mgol

@iham thanks a lot, you solve my problem and let me understand more what usemin does.

qcgm1978 avatar Nov 08 '13 09:11 qcgm1978

I confirm @iham's solution worked for me as well. I suggest it is the default for the webapp generator.

fernandoacorreia avatar Dec 10 '13 14:12 fernandoacorreia

Would be fixed when #244 shipped. But as said by @robwierzbowski it's safest to do html minification last

stephanebachelier avatar Feb 23 '15 23:02 stephanebachelier