4

I am trying to use grunt-contrib-html to minify my html. The only problem that I am using knockout with containerless control flow syntax, which is just html comments, but they are really important to knockout:

<ul>
    <li>This item always appears</li>
    <!-- ko if: someExpressionGoesHere -->
        <li>I want to make this item present/absent dynamically</li>
    <!-- /ko -->
</ul>

<!-- ko foreach: myItems -->
    <li>Item <span data-bind="text: $data"></span></li>
<!-- /ko -->

So when I use minifier with the following options:

options: {
   removeComments: true,
   collapseWhitespace: true
}

the application is not working after minification (not surprise, it removes <!-- ko comments ). Removing removeComments solves the problem, but my html has a lot of comments and only few of them are knockout specific. Moreover all knockout comments are easily recognizable: they have <!-- ko in the beginning and <!-- /ko --> in the end.

Looking for underlying html minifier options - there is nothing like "handle correctly knockout comments".

So is there a way to solve my problem: minify html removing comments, but leaving knockout specific comments?

Salvador Dali
  • 214,103
  • 147
  • 703
  • 753
  • 1
    I'm afraid you are out of look here. It is not supported without modifying the source of html-minifier or kncockout. Because the html-minifier supports ignoring the commnets with the sysntax : `` but this extra `!` is supported by KO is it does not recognizes the comment as KO comment. So you should probably open an issue about this problem on one of (or both) projects. – nemesv Mar 21 '14 at 05:42
  • Thanks @nemesv I am going to ask them for this feature. I knew that most probably this is impossible to achieve right now, but I need some knockout pro to verify it. – Salvador Dali Mar 21 '14 at 05:57
  • 1
    Feel free to open html-minifier issue — http://github.com/kangax/html-minifier I think we can totally try to accommodate this case. – kangax Mar 22 '14 at 02:25
  • @kangax thanks, the issue has been opened: https://github.com/kangax/html-minifier/issues/145 – Salvador Dali Mar 22 '14 at 04:38

2 Answers2

9

So... this is now implemented via ignoreCustomComments option.

Here's a snippet from our test suite:

var input = '<!-- ko if: someExpressionGoesHere --><li>test</li><!-- /ko -->';

equal(minify(input, {
  removeComments: true,
  // ignore knockout comments
  ignoreCustomComments: [
    /^\s+ko/,
    /\/ko\s+$/
  ]
}), input);
kangax
  • 38,898
  • 13
  • 99
  • 135
  • You can simplify the regex with this single entry: `/^\s+\/?ko/`. Also, if you want to use this on the command line you have to double-escape the slashes: `html-minifier --file-ext html --remove-comments --ignore-custom-comments \/^\\s+\\/?ko\/`. – Soulriser Sep 04 '19 at 00:15
0

If, for whatever reason, you still want to use containerless control flow without putting comment markup in your code, I've written a binding handler that will do it for you.

Apply it like so:

<div data-bind="wrap: {foreach: arr}" data-bind-inner="text: $data"></div>

with the binding for the container included as the data-bind attribute and the binding for the element itself as the data-bind-inner attribute. The handler actually creates comment tags and applies the specified binding to them, so there's nothing really tricky going on.

ko.bindingHandlers.wrap = {
  init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
    var outerBinding = valueAccessor(),
      vNodeOpen = document.createComment('ko'),
      vNodeClose = document.createComment('/ko');
    element.dataset.bind = element.dataset.bindInner;
    // Enclose element in comment nodes
    element.parentNode.insertBefore(vNodeClose, element);
    element.parentNode.insertBefore(element, vNodeClose);
    element.parentNode.insertBefore(vNodeOpen, element);
    ko.applyBindingsToNode(vNodeOpen, outerBinding, bindingContext);
  }
};

Demo fiddle

As written, it applies to a single node (with its descendant nodes, of course); you can't wrap a pair of siblings, but it could be extended to take a siblingCount option.

Roy J
  • 42,522
  • 10
  • 78
  • 102