WebMarkupMin: Minimizing KnockoutJS and AngularJS Views

    WebMarkupMin, KnockoutJS, and AngularJS Logos
    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:
    1. 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.
    2. 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 .
    3. 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:
    PropertyData typeDefault valueDescription
    ProcessableScriptTypeListLineEmpty lineContains 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.
    MinifyKnockoutBindingExpressionsBooleanfalseA flag that minimizes Knockout binding expressions in attributes data-bindand containerless comments.
    MinifyAngularBindingExpressionsBooleanfalseA flag that minimizes Angular binding expressions in Mustache-like tags ( {{ }}) and directives.
    CustomAngularDirectiveListLineEmpty lineContains a comma-separated list of custom Angular directives (for example, myDir,btfCarousel) that contain binding expressions. If the property value MinifyAngularBindingExpressionsis equal true, then expressions in user directives will be minimized.
    Let's consider each property in more detail:

    ProcessableScriptTypeList


    Prior to version 0.9.0, tags scriptthat 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 scriptcontains 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:
    1. If you want to minimize Knockout views, then ProcessableScriptTypeListyou need to set the property to equal text/html.
    2. If we are dealing with Angular views, then - text/ng-template.
    3. 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-tmplfor Kendo MVVM views that are not much different from Knockout).

    MinifyKnockoutBindingExpressions


    Usually when I talk about WebMarkupMin, I use the file code shell.htmlfrom 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 MinifyKnockoutBindingExpressionsassign 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 ( MsAjaxJsMinifierand are YuiJsMinifiernot 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 CrockfordJsMinifierproblem 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 MinifyAngularBindingExpressionsassigned 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:
    1. As elements
    2. As attributes
    3. Like attribute content class
    4. As comments

    Directive names can also have different spellings. For example, the directive ngBindhas 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, ngSubmitand ngSwitch.

    Items


    The HTML minimizer handles just one element directive - ngPluralize. More specifically, the expressions in the countand 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-bindin 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 classcan 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 CustomAngularDirectiveListwill 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:

    HTML Minimization Settings in Web Essentials 2013 (version 2.3.4.1)

    References


    1. WebMarkupMin Project Page on CodePlex
    2. Article «WebMarkupMin HTML Minifier - modern HTML-minimizer for .NET"
    3. Official Web Essentials extension
    4. The article "HTML minimization in Web Essentials 2013"
    5. 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.

    Also popular now: