Frage

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?

War es hilfreich?

Lösung

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);

Andere Tipps

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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top