
WebMarkupMin: Minimizing KnockoutJS and AngularJS Views

Starting from version 0.9.0, WebMarkupMin supports minimizing the views of KnockoutJS (hereinafter simply Knockout) and AngularJS (hereinafter simply Angular). Many of you may ask, “Why Knockout and Angular, not Mustache or Underscore ?” This choice was made for the following reasons:
- DOM based templates. The template engines built into Knockout and Angular are based on DOM-based templates, rather than string-based templates like Mustache and Underscore. The code of such templates does not contain program inserts (for example,
{{…}}
or<%…%>
) outside the text content of elements (tags) and attribute values, which allows you to minimize it like normal HTML. - Popularity among .NET developers. Knockout was originally created for .NET developers to allow them to transfer their MVVM application development experience from WPF and Silverlight to the regular web. As for Angular, it does not need to be introduced at all and its popularity among web developers as a whole breaks all possible records. In addition to the popularity of these libraries among .NET developers, a huge number of articles by Microsoft Evangelist John Papa contributed .
- Highly efficient binding expression compression. Binding expressions in Knockout and Angular are in fact simple JavaScript code or JSON-formatted objects that can be compressed with a JS minimizer.
New configuration properties
By default, minimization of views is disabled, and to enable it you need to change the values of the following class properties
HtmlMinificationSettings
:Property | Data type | Default value | Description |
---|---|---|---|
ProcessableScriptTypeList | Line | Empty line | Contains a comma-separated list of tag types script (for example text/html,text/ng-template ), the contents of which should be processed by an HTML minimizer. |
MinifyKnockoutBindingExpressions | Boolean | false | A flag that minimizes Knockout binding expressions in attributes data-bind and containerless comments. |
MinifyAngularBindingExpressions | Boolean | false | A flag that minimizes Angular binding expressions in Mustache-like tags ( {{ }} ) and directives. |
CustomAngularDirectiveList | Line | Empty line | Contains a comma-separated list of custom Angular directives (for example, myDir,btfCarousel ) that contain binding expressions. If the property value MinifyAngularBindingExpressions is equal true , then expressions in user directives will be minimized. |
ProcessableScriptTypeList
Prior to version 0.9.0, tags
script
that did not contain JavaScript code were simply ignored by the HTML minimizer. This was done because these tags can contain anything from VBScript code to Handlebars templates. But at the same time, if the tag script
contains the code of the DOM-template, then it would be worth passing through the HTML-minimizer. Therefore, users were given the opportunity to determine the list of acceptable content types themselves. Returning to the topic of the article, I will give a few examples:
- If you want to minimize Knockout views, then
ProcessableScriptTypeList
you need to set the property to equaltext/html
. - If we are dealing with Angular views, then -
text/ng-template
. - If the project uses two libraries at once, then you need to list content types, separated by commas:
text/html,text/ng-template
.
You also need to understand that we are not limited only to Knockout and Angular, theoretically we have the ability to minimize any DOM-based template (for example, we can specify the content type
text/x-kendo-tmpl
for Kendo MVVM views that are not much different from Knockout).MinifyKnockoutBindingExpressions
Usually when I talk about WebMarkupMin, I use the file code
shell.html
from the HotTowel demo project as an example :
After minimization, this code takes the following form:
It is immediately evident that binding expressions (hereinafter simply expressions) in containerless comments (the so-called containerless control flow syntax ) contain too many whitespace characters and they should be minimized.
Take for example an expression
compose: {view: 'nav'}
that, in essence, is an object in JSON format without external curly braces. We can wrap it in braces:, {compose: {view: 'nav'}}
and process it with a JS minimizer. Then, remove the curly braces from the minimized code and return it back to the containerless comment. If you
MinifyKnockoutBindingExpressions
assign an equal value to the property true
, then all the actions described above will be applied to the expressions. For these purposes, the JS minimizer is always usedCrockfordJsMinifier
, because only it can correctly minimize JSON code ( MsAjaxJsMinifier
and are YuiJsMinifier
not suitable for this purpose). With the new settings, we get the following code:
The same actions are performed with attributes
data-bind
. For example, we have the following code:
After minimization, it will look like this:
MinifyAngularBindingExpressions
According to the documentation , expressions in Angular are JavaScript-like code snippets. However, they can be minimized with
CrockfordJsMinifier
. The only problem was the one-time binding expressions (starting with ::
). The original JSMin always removed whitespace before them, but after making minor changes to the code, the CrockfordJsMinifier
problem was fixed. In Angular, expressions can be contained in Mustache-like tags (
{{ }}
) and directives. In turn, Mustache-like tags can be in the text content of elements:
Price: {{ 3 * 10 | currency }}
and in attribute values:

Accordingly, if the property is
MinifyAngularBindingExpressions
assigned a value equal to true
, we get the following results:Price: {{3*10|currency}}
and
Directives are much more complicated. In the template code, directives can be represented in 4 ways:
- As elements
- As attributes
- Like attribute content
class
- As comments
Directive names can also have different spellings. For example, the directive
ngBind
has the following options:ng-bind
ng:bind
ng_bind
x-ng-bind
data-ng-bind
All these features are taken into account when minimizing.
In addition, not all directives contain expressions. Some directives may also contain: templates, simple values, or nothing at all. In order to separate directives which contain the expression of other directives using the following list:
ngBind
, ngBindHtml
, ngBlur
, ngChange
, ngChecked
, ngClass
, ngClassEven
, ngClassOdd
, ngClick
, ngController
, ngCopy
, ngCut
, ngDblclick
, ngDisabled
, ngFocus
, ngHide
, ngIf
, ngInit
, ngKeydown
, ngKeypress
, ngKeyup
, ngModelOptions
, ngMousedown
, ngMouseenter
, ngMouseleave
, ngMousemove
, ngMouseover
, ngMouseup
, ngOpen
, ngPaste
, ngReadonly
, ngRepeat
, ngRepeatStart
, ngSelected
, ngShow
,ngStyle
, ngSubmit
and ngSwitch
.Items
The HTML minimizer handles just one element directive -
ngPluralize
. More specifically, the expressions in the count
and attributes are minimized when
. Suppose we have the following code:
After minimization, it will look like this:
Attributes
Minimizing expressions in attribute directives in Angular is even easier than minimizing the contents of attributes
data-bind
in Knockout, because you don’t have to think about external curly braces. Consider minimizing expressions in attribute directives using the example of a directive
ngRepeat
:
{{customer.name}} - {{customer.city}}
Despite the fact that the attribute contains “incorrect” code (from the point of view of JavaScript), minimization still succeeds:
{{customer.name}} - {{customer.city}}
Classes
The main difference between directive classes and attribute directives is that an attribute
class
can contain several directives at once:
This problem was also solved:
Comments
Unfortunately, Angular does not have a single built-in directive that could be presented as a comment. Therefore, we will consider a slightly contrived example where a user directive will be used as a comment directive
myDir
:
After minimization, we get the following code:
CustomAngularDirectiveList
Since Angular has the ability to create its own directives, users were given the opportunity to add the names of these directives to a special list. Custom directives specified in the property
CustomAngularDirectiveList
will be processed by the minimizer as well as the Angular built-in directives.Support in Web Essentials 2013
If you store your views in separate HTML files, then the standard ASP.NET extensions bundled with WebMarkupMin will be of little use. In this case, you need a fundamentally different tool that will minimize the HTML files at the assembly stage of the project. At the moment there is only one such tool - this is a VS-extension of Web Essentials 2013 .
The latest stable version of Web Essentials 2013 (version 2.3) supports the old version of WebMarkupMin (version 0.8.21). Therefore, you will need to install the night build of Web Essentials 2013 (there is an installation guide on the extension site ).
Last, at the time of writing, the nightly build (version 2.3.4.1) supports WebMarkupMin 0.9.3 and allows you to configure all the configuration properties considered:

References
- WebMarkupMin Project Page on CodePlex
- Article «WebMarkupMin HTML Minifier - modern HTML-minimizer for .NET"
- Official Web Essentials extension
- The article "HTML minimization in Web Essentials 2013"
- The article "HTML minimization in Web Essentials 2013: What has changed over the year?"
UPD1: On October 17, a stable version of Web Essentials 2013 (version 2.4) was released, which supports all the functionality presented.