Share your code. npm Orgs help your team discover, share, and reuse code. Create a free org »

    conkittypublic

    Conkitty Template Engine Build Status

    Conkitty templates are being compiled to concat.js chains. It is not a regular template engine, it doesn't produce strings of HTML, but generates DOM instead.

    Documentation is in painful progress, but it is better than nothing.

    Quick start

    Three quick start options are available:

    • npm install -g conkitty and conkitty -c common.js -t tpl.js file.ctpl will compile file.ctpl to common.js and tpl.js files.
    • Use grunt-conkitty to build Conkitty templates with Grunt, check out this example.
    • Use gulp-conkitty to build Conkitty templates with Gulp, check out this example (it has example dependencies).

    Compiled templates consist of two and a half parts:

    • Common core code needed for runtime,
    • compiled templates code,
    • external dependencies (in case they are declared in templates).

    To start using compiled templates, link common core and compiled templates to your page with <script> tags.

    There is a Conkitty syntax highlighting plugin for JetBrains products (IntelliJ IDEA, WebStorm, PhpStorm and so on). It is available from official plugin repository.

    <html>
        <head>
            <title>Hello</title>
        </head>
        <body>
            <script src="/path/to/common.js"></script> 
            <script src="/path/to/compiled/templates.js"></script> 
            <script>
                // Insert `template-name` result into document body right away. 
                $C.tpl['template-name'].call(document.body, 'Hello', [1, 2, 3], {k1: 'v1', k2: 'v2'});
     
                // The same, but assign generated DOM to a variable. 
                var rendered = $C.tpl['template-name']('Hello', [1, 2, 3], {k1: 'v1', k2: 'v2'});
                document.body.appendChild(rendered);
                // `rendered` is a document fragment, so, it's not a valid reference 
                // after you call appendChild for it. 
            </script> 
        </body>
    </html>

    Syntax

    Block nesting is done via indentation. Top level (zero-indented lines) is for templates declarations. Below each template declaration are commands, tags, strings, variables and JavaScript expressions.

    template-name $arg1 $arg2 $arg3
        h1
            $arg1
        ul
            EACH $item $arg2
                li
                    "Item: "
                    $item
        dl
            EACH $key $val $arg3
                dt
                    $key
                dd
                    $val
    
    // $C.tpl['template-name']('Hello', [1, 2, 3], {k1: 'v1', k2: 'v2'}) will produce:
    //
    // <h1>Hello</h1>
    // <ul>
    //     <li>Item: 1</li>
    //     <li>Item: 2</li>
    //     <li>Item: 3</li>
    // </ul>
    // <dl>
    //     <dt>k1</dt>
    //     <dd>v1</dd>
    //     <dt>k2</dt>
    //     <dd>v2</dd>
    // </dl>
    

    Template declaration

    template-name [$arg1 [$arg2 […]]]

    Where template-name is a name of the template, this name is used to call the template. When you call the template, you can pass any number of arguments to it. These arguments will be accessible from JavaScript expressions of the template via appropriate names. Argument names should be a $ sign plus a valid JavaScript variable names.

    template1 $arg1 $arg2
        h1
            $arg1
        p
            ($arg2 + ' ' + $arg2) // JavaScript expression, arguments are
                                  // accessible here too.
    
    // $C.tpl.template1('Hello', 'World') will produce:
    //
    //  <h1>Hello</h1>
    //  <p>World World</p>
    

    You can specify default values for arguments.

    template2 $arg1="Hello" $arg2=({a: 1, b: 2})
        h1
            $arg1
        p
            (JSON.stringify($arg2))
    
    // $C.tpl.template2('Pillow', 'World') will produce:
    //
    //  <h1>Pillow</h1>
    //  <p>"World"</p>
    
    // $C.tpl.template2() will produce:
    //
    //  <h1>Hello</h1>
    //  <p>{"a":1,"b":2}</p>
    

    Strings

    Strings are enclosed in single or double quotes. String should begin and end in the same line. String will be properly escaped in the result.

    Good

    "Hello world"
    
    'Hello \'world\''
    
    "Hello <world>"
    

    Bad

    "Hello
       world"
    

    JavaScript expressions

    JavaScript expressions are enclosed in parenthesis. A JavaScript expression value will be coerced to string and properly escaped in the result. You can pass a function expression, this function will be called.

    Good

    (1 + 2 + 3)
    
    ('Hello ' + Math.random() + ' world')
    
    (function() {
         // Expressions could be multiline.
         // `this` is pointing to current DOM node.
         return this.innerHTML + this.innerHTML;
    })
    

    Bad

    ()
    
    (())
    
    (return 123)
    

    Tags

    Use CSS selector-like constructions to create tags.

    // Create <div class="test"></div>
    div.test
    
    // Create <a id="ppp" class="hello world" href="http://conkitty.io"></a>
    a#ppp.hello.world[href="http://conkitty.io/"]
    
    // Create <a href="http://conkitty.io" data-rnd="0.8223862457089126">Yo</a>
    a
        @href "http://conkitty.io/"
        @data-rnd (Math.random())
        "Yo"
    // or
    a[href="http://conkitty.io/"][data-rnd=(Math.random())]
        "Yo"
    

    There are :if(expr, trueSelector, falseSelector) and :elem(expr) pseudo selectors.

    template $arg1 $arg2
        strong:if($arg1, .arg1-is-true#piu, [data-something="yes"])
            "Hello"
        #identifier:elem($arg2)
            "World"
    
    // $C.tpl.template(true, 'em') will produce:
    //
    //  <strong class="arg1-is-true" id="piu">Hello</strong>
    //  <em id="identifier">World</em>
    
    // $C.tpl.template(false, 'span') will produce:
    //
    //  <strong data-something="yes">Hello</strong>
    //  <span id="identifier">World</span>
    

    There are several ways to specify attributes:

    • [attr=val] parts of selectors,
    • @attr val below selectors,
    • ATTR command (see this command description below).
    template $val2 $val5
        div.class1[attr1="val1"][attr2=$val2][attr3=('val' + 3)]
            @attr4 "val4"
            @attr5 $val5
            @attr6 ('val' + 6)
            // Special case for `class` attribute, you can add, subtract and
            // use selector syntax:
            @class +.class2.class3  // Add using selector syntax.
            @class -.class2         // Subtract using selector syntax.
            @class +"class4 class5" // Add.
    
    // $C.tpl.template('val222', 'val555') will produce:
    //
    // <div class="class1 class3 class4 class5"
    //      attr1="val1"
    //      attr2="val222"
    //      attr3="val3"
    //      attr4="val4"
    //      attr5="val555"
    //      attr6="val6"></div>
    

    Variables

    A number of variables could be accessible inside a template. Template arguments, SET, EACH and WITH commands, AS $var constructions create variables inside a template. Variable names should be a $ sign followed by a valid JavaScript variable name, all template variables are accessible in template JavaScript expressions via their names.

    template $arg1 $arg2
        SET $var1 $arg1
        SET $var2 ('Concatenated ' + $arg2 + $arg2)
        $arg1
        ($var1 + ' piu ' + $arg2)
        $var2
    

    Commands

    ATTR name value

    This command should be used to add an attribute with a dynamic name.

    name and value are strings, variables or JavaScript expressions.

    // Create
    // <div id="yep"></div>
    // or
    // <div class="yep"></div>
    div
        ATTR (Math.random() < 0.5 ? 'id' : 'class') "yep"
    

    CALL template-name [arg1 [arg2 […]]]

    You can call one template from another. argN are arguments for a template. Arguments should be strings, variables or JavaScript expressions.

    template1
        div
            CALL template2 "Hello" (' wo' + 'rld')
    
    template2 $arg1 $arg2
        h1
            $arg1
            $arg2
            "!"
    
    // $C.tpl.template1() will produce:
    //
    // <div>
    //     <h1>Hello world!</h1>
    // </div>
    

    You can pass arguments by names.

    template1
        div
            // Notice that `$` signs in argument names should not present here.
            CALL template2 "111" "22" a6=('si' + 'x') a4="ffff"
    
    // Say, we have a template with a bunch of arguments with default values.
    template2 $a1="1" $a2="2" $a3="3" $a4="4" $a5="5" $a6="6"
        h1
            $a1
        h2
            $a2
        h3
            $a3
        h4
            $a4
        h5
            $a5
        h6
            $a6
    
    // $C.tpl.template1() will produce:
    //
    // <div>
    //     <h1>111</h1>
    //     <h2>22</h2>
    //     <h3>3</h3>
    //     <h4>ffff</h4>
    //     <h5>5</h5>
    //     <h6>six</h6>
    // </div>
    

    Additionally, you can pass a subtree when you call a template.

    template1
        div
            CALL template2 "Hello world"
                // This is PAYLOAD for template2, it will be calculated lazily
                // when (and if) you use PAYLOAD command inside template2.
                span
                    "!"
    
    template2 $arg1
        h1
            $arg1
            PAYLOAD
    
    // $C.tpl.template1() will produce:
    //
    // <div>
    //     <h1>Hello world<span>!</span></h1>
    // </div>
    

    It is possible to get template name dynamically, as JavaScript expression.

    template1
        div
            CALL ('template' + 2) "Hello" "world"
    
    template2 $arg1 $arg2
        $arg1
        " "
        $arg2
    

    You can compliment CALL command with EXCEPT section, which will be executed in case of any exception during CALL command processing.

    template1
        div
            CALL template2
                // Payload could be here too.
            EXCEPT
                "Oops"
    
        div
            CALL (function() { throw new Error('Template name getter exception'); })
            EXCEPT
                "It is safe"
    
    template2
        span
            JS
                throw new Error('Exception, baby')
    

    CHOOSE

    CHOOSE is a command to choose one of multiple choices.

    template $arg1
        CHOOSE
            WHEN ($arg1 === 1)
                div
                    "111"
            WHEN $arg1
                span
                    "222"
            OTHERWISE
                p
                    ($arg1 + ' aaa ' + $arg1)
    
    // $C.tpl.template(1) will produce: <div>111</div>.
    // $C.tpl.template(2) will produce: <span>222</span>.
    // $C.tpl.template(false) will produce: <p>false aaa false</p>.
    

    Any number of WHEN sections is possible. OTHERWISE section is optional.

    EACH [$key] $value expr

    Iterate over an array or an object.

    $key and $value are references to items you're being iterating through. They should be a $ sign plus a valid JavaScript variable name. $key is optional.

    expr is a variable or a JavaScript expression returns an array or an object.

    template
        EACH $val ([11, 22])
            p
                ($val + ' aa ' + $val)
    
        EACH $index $val ([33, 44])
            span
                $index
                ": "
                $val
    
        EACH $vvv ({k1: 'v1', k2: 'v2'})
            div
                $vvv
    
        EACH $k $v ({k3: 'v3', k4: 'v4'})
            em
                $k
                ": "
                $v
    
    // $C.tpl.template() will produce:
    //
    // <p>11 aa 11</p>
    // <p>22 aa 22</p>
    // <span>0: 33</span>
    // <span>1: 44</span>
    // <div>v1</div>
    // <div>v2</div>
    // <em>k3: v3</em>
    // <em>k4: v4</em>
    

    It is possible to add fallback for an empty array (or object):

    template
        ul
            EACH $val ([])
                li
                    $val
            ELSE
                li.empty
                    "No items."
    
        EACH $key $val ({})
            p
                $key
                ": "
                $val
        ELSE
            em
                "Empty."
    

    JS [$item $index $obj]

    Run arbitrary JavaScript code.

    $item, $index and $obj are references to current context items.

    Everything that's below JS command with higher indentation will be executed as JavaScript code.

    template
        div
            JS
                window.everythingIsOk = true
            p
                "Hello world"
                JS
                    var y = 'y',
                        e = 'e',
                        s = 's';
                    window.thisIsOkToo = y + e + s;
    
            ul
                EACH $i $v ([11, 22])
                    li
                        JS $item $index $arr
                            console.log($item === $v, $index === $i, $item, $arr);
                        $v
    
    
    // $C.tpl.template() will produce:
    //
    // <div>
    //     <p>Hello world</p>
    //     <ul>
    //         <li>11</li>
    //         <li>22</li>
    //     </ul>
    // </div>
    //
    // `window.everythingIsOk` and `window.thisIsOkToo` will be set to
    // `true` and 'yes' respectively, and there will be two lines in console
    // log: `true true 11 [11, 22]` and `true true 22 [11, 22]`.
    

    MEM key [expr]

    You have access to exact DOM nodes during their creation process. You can memorize some of these nodes for future use.

    template
        div
            MEM "my-div"
    
            p
                MEM ('my' + '-' + 'p') ({ppp: this})
    
    // $C.tpl.template();
    // `$C.mem` will be {'my-div': <div>, 'my-p': {'ppp': <p>}}
    

    SET $name expr

    $name is a $ sign plus a valid JavaScript variable name.

    expr is a JavaScript expression for a variable value.

    Sometimes you need to define a variable.

    template1
        div
            SET $myvar ({some: 'data', inside: '.'})
    
            EACH $val $myvar
                $val
    
            // You can reuse variable names.
            SET $myvar ({another: 'value'})
    
            ($myvar.another)
    
    // $C.tpl.template1() will produce:
    //
    // <div>data.value</div>
    

    You can also assign a subtree to a variable.

    template2
        SET $myvar2
            em
                "hello"
            strong
                "world"
    
        div
            // Use unescaped JavaScript expression (see below) to insert the result.
            ((($myvar2)))
    
    // $C.tpl.template2() will produce:
    //
    // <div>
    //     <em>hello</em>
    //     <strong>world</strong>
    // </div>
    

    TEST expr

    TEST is a simplified CHOOSE for the cases you have only one option to check.

    template $title
        TEST $title
            h1
                $title
        p
            "Some content"
    
    // $C.tpl.template('Tiiiiiii') will produce:
    //
    // <h1>Tiiiiiii</h1>
    // <p>Some content</p>
    
    // $C.tpl.template() will produce:
    //
    // <p>Some content</p>
    

    TRIGGER [arg1 [arg2 […]]]

    You can subscribe to TRIGGER command calls from your application:

    $C.on(function(arg1, arg2) {
        // `this` will be currently created DOM element.
        console.log(arg1, arg2, this);
    });
    

    After that:

    template
        div
            TRIGGER "some" ({arg: true})
            "Hello"
    
    // Calling $C.tpl.template.call(document.body) will add `<div>Hello</div>`
    // to `document.body` and print `some {arg: true} <div>Hello</div>` in your
    // console log.
    

    WITH $name expr

    $name is a $ sign plus a valid JavaScript variable name.

    expr is a JavaScript expression.

    template
        div
            SET $v ({a: {b: {c: 'd', e: false}}})
    
            div
                WITH $ok ($v.a.b.c)
                    $ok
                ELSE
                    "HECK"
    
            div
                // Go to ELSE section in case of exception.
                WITH $ok ($v.e.f.g)
                    $ok
                ELSE
                    "HECK"
    
            div
                WITH $ok ($v.a.b.e)
                    $ok
                ELSE
                    "HECK"
    
            div
                // Go to ELSE section in case of undefined value.
                WITH $ok ($v.a.b.no)
                    $ok
                ELSE
                    "HECK"
    
    // $C.tpl.template() will produce:
    //
    // <div>
    //     <div>d</div>
    //     <div>HECK</div>
    //     <div>false</div>
    //     <div>HECK</div>
    // </div>
    

    Unescaped strings

    A string like "&nbsp;" will produce &amp;nbsp; in the result. To put an unescaped text to the result, enclose a string in triple quotes. Note that the markup inside triple quotes should be valid.

    Good

    """Hello&nbsp;world"""
    
    '''<p>Hello <strong>world</strong></p>'''
    

    Bad

    """</div>"""
    

    Unescaped JavaScript expressions

    When you use a JavaScript expression to insert something to the result, its value is coerced to a properly escaped string. Sometimes you have a DOM node as a template argument or you want to insert an unescaped JavaScript expression value. To do that, enclose your JavaScript expression in triple parenthesis. When you do that, typecheck is performed, if your JavaScript expression value is an instance of Node, it will be inserted as node, otherwise the value will be coerced to a string and this string will be inserted unescaped (note that the markup should be valid).

    Please, keep in mind, that if you need unescaped JavaScript expressions often, you are probably doing something wrong.

    template1
        div
            CALL template2
                span
                    "some DOM inside"
    
            ('<em>' + 'no, it is not' + '</em>')
            ((('<strong>' + 'yes, it is' + '</strong>')))
    
    template2
        p
            // Pass this template's PAYLOAD as an argument to next template.
            CALL template3 PAYLOAD
    
    template3 $arg
        "This is not "
    
        $arg
    
        ", this is "
    
        ((($arg)))
    
        " indeed."
    
    // $C.tpl.template1() will produce:
    //
    // <div>
    //     <p>
    //         This is not [object DocumentFragment], this is <span>some DOM inside</span> indeed.
    //     </p>
    //     &lt;em&gt;no, it is not&lt;/em&gt;
    //     <strong>yes, it is</strong>
    // </div>
    

    Line wrap

    Templates can accept many arguments, selectors could be pretty long. It is possible to split command into several lines. When parser meets \, it skips all the whitespaces after and continues with first non-whitespace character.

    template1
        CALL template2  \
            "Argument1" \
            "Argument2" \
            "Argument3"
    
    template2 $arg1 $arg2 $arg3
        div.class1\
                  [attr1=$arg1]\
                  [attr2=$arg2]\
                  [attr3=$arg3]            
            "Hello"
    
    // $C.tpl.template1() will produce:
    //
    // <div class="class1" attr1="Argument1" attr2="Argument2" attr3="Argument3">Hello</div>
    

    Namespaced templates

    When you build a set of files, all the templates go to compiled result. But you can declare namespaced templates, they will go to the result only in case they are used from regular templates.

    Namespaced templates can be called from regular templates and can't be called directly using $C.tpl[name] functions.

    // Regular template, will go to the result anyway.
    template
        div
            CALL ns1::template1 "World"
    
            // You can skip `CALL` keyword when you call namespaced template:
            ns1::template1 "Pillow"
    
    // Namespaced template, will go to the result because it's used from regular template above.
    ns1::template1 $arg
        span
            "Hello "
            $arg
    
    // Another namespaced template, will not appear in the result since it's not used.
    another-ns::template1
        strong
            "No way"
    
    // $C.tpl.template() will produce:
    //
    // <div>
    //     <span>Hello World</span>
    //     <span>Hello Pillow</span>
    // </div>
    

    It is possible to skip CALL keyword, when you call namespaced templates.

    Remembering created nodes

    Conkitty is a DOM generator, not a string generator. As a benefit, you have an access to exact DOM nodes during their creation process. You can push these nodes back to your application using TRIGGER and MEM commands. But you also can assign nodes to variables with AS $varName constructions.

    template
        div
            span.hello AS $mySpan
            em.world AS $world
    
        // Now you have `<span>` in `$mySpan` and `<em>` in `$world`.
        // You can pass them to other templates or do something sophisticated with them.
        JS
            $mySpan.innerHTML = 'Hello';
            $world.innerHTML = ' beautiful world';
    
    // $C.tpl.template() will produce:
    //
    // <div>
    //     <span class="hello">Hello</span>
    //     <em class="world"> beautiful world</em>
    // </div>
    

    Returning more from templates

    You can return complex structures from templates, this is useful when you create reusable components (for example, you can return component's API).

    Use EXPOSE command in combination with string, variable, expression or JS command to return value and AS $varName construction to get returned value.

    template
        div
            // $btn will have `{btn: <button>, title: <span>}`
            ctrl::button "My sweet button" AS $btn
    
            JS
                $btn.title.innerHTML += '!!!';
    
    ctrl::button $title $type="button"
        button[type=$type] AS $btnNode
            span AS $titleNode
                $title
    
        EXPOSE ({btn: $btnNode, title: $titleNode})
    
        // Or the same with `JS` command:
        //
        // EXPOSE JS
        //     return {btn: $btnNode, title: $titleNode}
        //
        // Or the same with variable:
        //
        // SET $ret ({btn: $btnNode, title: $titleNode})
        // EXPOSE $ret
    
    // $C.tpl.template() will produce:
    //
    // <div>
    //     <button type="button">
    //         <span>My sweet button!!!</span>
    //     </button>
    // </div>
    

    Only one EXPOSE command per template is allowed.

    You can return values from regular templates too and have them as the result of template function call.

    template1
        div
            "Hello World"
    
    template2
        div AS $d
            "Hello World"
        EXPOSE ({elem: $d, ololo: 'something else'})
    

    Feel the difference in calls below.

    var ret;
     
    ret = $C.tpl.template1();
    // `ret` is a document fragment with `<div>Hello World</div>` inside. 
     
    ret = $C.tpl.template1.call(document.body);
    // `ret` is undefined and `<div>Hello World</div>` is added to `<body>`. 
     
    ret = $C.tpl.template2();
    // `ret` is `{elem: <div>, ololo: 'something else'}`. 
     
    ret = $C.tpl.template2.call(document.body);
    // `ret` is `{elem: <div>, ololo: 'something else'}` and 
    // `<div>Hello World</div>` is added to `<body>`. 

    Node appender

    If you have DOM node in a variable (or as an expression result), you can use Conkitty syntax to modify attributes and add children to this node. Use ^ operator for this.

    template1
        div.hello AS $myDiv
            CALL template2 $myDiv
    
        div.world AS $myDiv2
        CALL template2 $myDiv2
    
    template2 $div
        strong
            "Yo"
    
        // Manipulations with $div node.
        TEST $div
            ^$div
                @class +.class1.class2
                span
                    "Hello"
    
        em
            "Yep"
    
    // $C.tpl.template1() will produce (notice node order):
    //
    // <div class="hello class1 class2">
    //     <span>Hello</span>
    //     <strong>Yo</strong>
    //     <em>Yep</em>
    // </div>
    // <div class="hello class1 class2">
    //     <span>Hello</span>
    // </div>
    // <strong>Yo</strong>
    // <em>Yep</em>
    

    External files dependency declaration

    It often happens that you need some additional dependencies for your templates (such as stylesheets, JavaScript files or images).

    It is possible to declare these dependencies and have their properly ordered list along with compiled templates. Use & operator for this.

    Say, you have tpl.ctpl file like this:

    template
        &"file1.css"
        &"file1.js"
        div
            ctrl::button "My button"
    
    // You can declare namespace-wide dependencies (they will go to the result
    // in case any template of this namespace is used in regular templates).
    ctrl::
        &"ctrl.css"
        &"ctrl.js"
    
    ctrl::button $title $type="button"
        &"button.css"
        button[type=$type]
            $title
    
    // Will not appear in the result since not used.
    ctrl::input $name
        &"input.css"
        input[type="text"][name=$name]
    
    // Will not appear in the result since not used.
    aaa::
        &"aaa.css"
    
    // Will not appear in the result since not used.
    aaa::template
        &"aaa.js"
    

    conkitty command line tool has --deps option, it means filename to put dependencies list to. grunt-conkitty has deps option too, for Grunt plugin it means directory to copy all the dependencies to.

    Let's use command line tool like conkitty --common=common.js --templates=tpl.js --deps=deps.txt tpl.ctpl

    deps.txt will be:

    /absolute/path/to/ctrl.css
    /absolute/path/to/ctrl.js
    /absolute/path/to/button.css
    /absolute/path/to/file1.css
    /absolute/path/to/file1.js
    

    Precompile expressions

    Precompile expressions are a kind of black voodoo and should be used in exceptional cases only.

    Precompile expressions are JavaScript expressions that are evaluated by template parser. Precompile expression should start with |( and end with )|.

    For example, we have a template like this:

    template|('-suffix' + prop1)|
        &|('"style.' + prop2 + '.css"')|
        p|(prop3 ? '.class1' : '')|
            "Hello"
    

    In this example prop1, prop2 and prop3 are keys of environment object passed to Conkitty constructor. Here is the actual template that will be compiled if we pass environment object like {prop1: 111, prop2: 'dark', prop3: true}:

    template-suffix111
        &"style.dark.css"
        p.class1
            "Hello"
    

    Generated code notes

    Generated code for a template like:

    b-checkbox $props
        div.checkbox
            label
                input[type="checkbox"][name=($props.name)][id=($props.id)][value=($props.value)]
                TEST ($props.label)
                    em
                        ($props.label)
    

    will look like:

    $C.tpl["b-checkbox"] = function($props) {
        var $ConkittyEnv = $ConkittyGetEnv(this);
        return $C($ConkittyEnv.p)
            .div({"class": "checkbox"})
                .elem("label")
                    .elem("input", function $C_b_checkbox_4_13(){return{type:"checkbox",name:$props.name,id:$props.id,value:$props.value}})
                    .end()
                    .test(function $C_b_checkbox_5_18() { return ($props.label); })
                        .elem("em")
                            .text(function $C_b_checkbox_7_21() { return ($props.label); })
        .end(5);
    };
    

    You might notice anonymous functions named like $C_b_checkbox_7_21. These names are for easier debugging — you'll see template name, line number and character position in your call stack. JavaScript minifiers like UglifyJS remove these names during minification, so, compiled templates minify really well.

    Source maps

    Since version 0.5.7, Conkitty is capable of creating source maps for compiled templates.

    Check out gulp-conkitty and grunt-conkitty to see how to create source maps.

    Or use --sourcemap argument of command line utility:

    conkitty --common=common.js --templates=tpl.js --sourcemap=tpl.map tpl.ctpl
    

    When you compile templates with source map, //@ sourceMappingURL=your.source.map comment is being added on top of your compiled templates code.

    Performance notes

    It is hard to do adequate performance tests. I did simple ones like (simplified example):

    function render(parent, arr) {
        var ret,
            i;
     
        ret = '<ul>';
     
        for (= 0; i < arr.length; i++) {
            ret += '<li>' + arr[i] + '</li>';
        }
     
        ret += '</ul>';
     
        parent.innerHTML = ret;
    }
     
    render(document.body, [1, 2, 3, 4, 5])

    versus template:

    render $arr
        ul
            EACH $item $arr
                li
                    $item
    

    and template call:

    $C.tpl.render.call(document.body, [1, 2, 3, 4, 5])

    And first ones were about 50% faster. But there are at least three things to keep in mind:

    • After you've built DOM from HTML string, you need to spend some time traversing this DOM to find all key nodes your application needs. With Conkitty you don't need DOM traversals — you have access to exact DOM nodes during template execution.
    • Pages are mostly reasonably-sized. This means that even bigger performance difference will not have noticeable impact to application speed.
    • Many optimizations could be done in future (like merging adjacent text node generators into single expression). But because of first two things I clarify these optimizations as premature.

    install

    npm i conkitty

    Downloadsweekly downloads

    125

    version

    0.5.21

    license

    MIT

    repository

    github.com

    last publish

    collaborators

    • avatar