Key features for client-side templates

[update - January 18th, 2013]: the template engine described in this article is being implemented here

When we started working on client-side HTML templates three years ago we had a hard time convincing our colleagues that it was not a crazy idea and that we could build rich and efficient applications with this type of approach. Today the situation is different as there are many client-side template frameworks in the open-source landscape – and the W3C has even started working on specifications to include templates as part of the core browser technologies.

However, the actual features supported by the different template solutions are still rather heterogeneous, and they also differ in nature (e.g. template that generate HTML strings vs. template that manage automatic data-binding between the HTML DOM and the template data model). As such, I thought it would be interesting to step back and sort-out what should be – in my opinion – the key features of the next-generation client-side templates.

I know this is rather ambitious and bold, and many people have very sharp opinions on it – but the goal of this exercise is also to debate, so feel free to comment. So , as far as I am concerned, here is what I came up with:

  • Templates as functions
  • JSON as data objects
  • Natural syntax
  • No restriction on the HTML that can be generated
  • Control statements
  • Bi-directional data-binding, with adapters and validators support
  • Sub-template calls
  • Simple event handlers
  • Widgets / Component libraries
  • Internationalization / Localization
  • Visual transitions and dynamic CSS class support
  • Modular architecture: CSS and JS scoping, dependency management, etc
  • Security and HTML escaping
  • Fast initial rendering and SEO

Templates as functions

The purpose of HTML templates being to transform a data structure into HTML DOM elements, they constitute by nature dynamic entities that implement a functional behavior. Current template engines usually fall into 2 categories:

  • engines that generate HTML strings that have to be then injected into the HTML DOM (e.g. through the innerHTML method)
  • or engines that create a link between a root DOM element and a data model (e.g. JSON structure) in order to support bi-directional bindings, so that any change in the data model gets automatically reflected into the DOM

In the first case, it is quite natural to design the template as a functions that accepts some arguments (like the data model) and that returns an HTML string. In the second case, it is less obvious – although it is possible to consider the template as a function that generates binding objects between a root DOM element and data objects passed as arguments.

The benefit of considering and implementing templates as functions are multiple:

  • templates can be defined in one place, and used many times to implement multiple DOM instances (usually bound to different data objects)
  • multiple arguments can be passed to templates, making them highly flexible
  • sub-templates can be easily called with different arguments (e.g. a sub-set of the data model) – which makes libraries of all-purpose templates easy to support, as the template are not bound to global objects
  • in a functional environment such as JavaScript, templates can be passed as argument to other templates. This makes template expression power even more mighty.
  • in the case where templates are implemented as JavaScript functions, templates closures can attach other templates or JS functions that don’t need to be defined as global variables or as template arguments to be used in the template itself. This is an interesting feature to develop web components that cannot pollute the global scope – but there are of course other ways to reach this goal.

JSON as data objects

The template engine should not impose specific data structures. This is easy to say – but if we want to implement automatic data/DOM bindings, the template engine needs to be aware of changes in the data model to trigger DOM updates.
This is why many template engines have developed specific data-object frameworks (cf. ember framework) – but the drawback of this approach is that it impose rather heavy conventions.

The good news is that the JavaScript Object.observe proposal has been accepted by the ECMAScript committee, and that it should come soon to our browsers (should be available in Chrome as of ES6, though officially part of ES7 according to Rafael Weinstein from the Chrome team). Of course, it doesn’t mean that we will have the possibility to use it in our apps immediately – but at least application designs should take this new feature into account. For the time being, my recommendation would be to use a accessor library, as we did in aria templates, to manipulate data in a JSON structure and support data listeners stored as meta-data attached to the structure (not perfect but very simple and efficient). In practice code would look like this:

var person={
    lastName:"Allen",
    firstName:"",
    address:{
        city:"NYC"
    }
}

// set a listener (syntax should be as close as possible to Object.observe):
json.observe(person,function (changes) {/*...*/}); // creates a person["meta:listeners"] array and store information in it

// set a value:
json.set(person,"firstName","Woody");
// etc.

With this approach, refactoring code once Object.observe is available everywhere should be quite easy..

Natural syntax

Experience shows that syntax plays a key role in the adoption of a template solution. There are actually many trends in the current template landscape. One of the most popular approach is to consider templates as a new type of DOM elements (cf angular js). The main benefits are that

  • the template is written in the HTML DOM, so you get editors for free (any current HTML editor does the work)
  • the template is automatically loaded with your page – so the template load is well optimized (i.e. no asynchronous load is required)
  • the template is automatically parsed by the browser – so parsing is fast and doesn’t require to download of heavy JavaScript libraries.
    However it comes at a great expense as the template syntax becomes extremely constrained by the XML/HTML notation, which results in rather painful and verbose languages. Besides in most implementation, syntax constraints impose to create un-necessary HTML elements to manage control statements, which I think is not an acceptable trade-off.

Having said that, as the purpose of the HTML template is to produce HTML, I am also convinced that the template syntax should include the HTML tags as part of the template grammar – this allows for instance the template parser to raise errors in case of incorrect HTML structures (but there are more benefits as you will see below).

In the examples that appear in the next sections I decided to use a line-based language that mixes the HTML syntax – to describe the DOM elements that should be created by the template – and a JavaScript-inspired expression / instruction language for the other parts. It is currently not implemented and is used for illustration purposes only – but at least it shows that we can have a very readable template syntax (at least according to my own criteria..), provided that we get rid of the XML/HTML constraint. Technically this template syntax could be easily implemented as a JavaScript pre-processor that would transform each template into a JavaScript function.

As a first introduction, here is how a hello world template would look like:

    # template hello1
        Hello World!
    # /template

OK – that’s quite useless – so let’s add some dynamic behavior:

    # template hello2(person)
        <h1>Hello {person.name}</h1>
    # /template

No restriction on the HTML that can be generated

Before going into more detailed examples, I think there is a golden rule that all template languages should comply to, which is that any kind of valid XHTML should be possibly generated. The corollary is that the template syntax should not impose the creation of some DOM elements if not required (e.g. create a %lt;span> to manage a conditional display).

Conditional statements

I think this is the second golden rule: conditional statements such as if/for/foreach must be natively supported. They are just too obvious, and they should be supported as naturally as possible – e.g.:

    # template itemList(items)
        <div class="abc">
        # for (var key in items)
            # if (items[key])
                <span class="empty"> Item {key} is empty... </span>
            # else
                <span class="title"> Item {key}: </span>
                <span class="item"> {items[key].content} </span>
            # /if
        # /for
        </div>
    # /template

Bi-directional data-binding, with adapters and validators support

Data-binding is something that comes quite naturally when working with client-side templates, as it becomes quickly painful to have to write code to refresh / update the DOM anytime changes occur in the data-model.
In this respect the angular and google model-driven-views approaches are probably the most advanced solutions – and I think this the path future template engines should follow as they bring obvious simplifications for very classical UI use cases (cf. angular todo list example).

Of course, in an ideal world, binding syntax should be more or less transparent:

    # template main(person)
        <div class="person">
            // if person.firstName changes the following div should be updated 
            <div> First name: {person.firstName} </div>
            <div> Full name: {getFullName(person.title, person.firstName, person.lastName)} </div> 
            // getFullName is a JS function defined in the template JS scope
            // of course only the variables appearing in the binding expression (i.e. the arguments) should be considered to trigger DOM updates
        </div>
    # /template

Having said that, I see 2 important features that must be supported by template engines that implement data-binding:

  • template refresh cannot directly be triggered by the JS Object.observe layer in order to preserve the DOM from un-necessary changes. The very first example that comes to mind occurs when performing Array manipulations (e.g. sort, splice…) where we don’t want the template to display intermediate state of the Array. As such the template engine should offer a possibility to disconnect / buffer the automatic refresh and store the changes into a special stack – in other words, we need some transactional change features, with the possibility for application scripts to interact with this buffer (btw. R. Weinstein already started working on this topic – cf. ChangeSummary library )
  • the 2nd key feature is that template syntax must support optional adaptors and validators during the binding operation

bindings with data adaptors

In (frequent) cases the data available in the model are not exactly the one we want to display (or input) – so there is a need for an adaptor layer in order to adapt the data from the model to the view (and vice versa). Something like this could do the job:

    # template main(data)
        <div>
            <label>Number of miles:</label>
            // Miles are displayed in the UI - but the model is using kilometers
            <input type="text" placeholder="Enter a number here" value="{data.number>>kmToMiles}"/>
        </div>
    # /template

    // where kmToMiles would be a JS function looking like this:

    function kmToMiles(model, dom) {
        // model is in km, whereas UI is in miles
        var oneKM=0.621371192; // 1km in miles

        if (model.isChangeOrigin) {
            // data model changed => update the DOM value
            dom.value = model.value * oneKM; 
        } else {
            // dom.isChangeOrigin==true
            // a user entered a value in the DOM => update the model value
            model.value = dom.value / oneKM;
        }
    }

Note: if you wonder why I used the >> symbol instead of the | symbol (usually used for modifiers / filters), it is because the pipe sign has a special signification in JavaScript, and I think it would be good to consider the expression language as JS-compatible (cf. later paragraph on widgets / components)

Note 2: like for modifiers, we could imagine to chain adapters: *value=”{data.number>>positiveNbr>>kmToMiles}”*

bindings with validators

In also very frequent cases, the value entered in the UI should be considered as a formatted value – so that many user inputs may be considered incorrect as they may not match the expected format. IMO validators should be implemented as an extension of data adaptors – as illustrated below.

Note: even if the value entered by the user is incorrect (and as such must not be stored in the official property of the data model), the template engine must provide a way to keep and persist it as the user experience would be pretty bad otherwise – this is the goal of the text attribute in the following example:

    # template main(data)
        <div>
            <label>Enter your age: </label>
            <input type="text" value="{data.age>>checkAge}" text="{data.ageTxt}">
        </div>
    # /template

    function checkAge(model, dom) {
        if (dom.isChangeOrigin) {
            // calls an external function for age validation (RegExp, etc.)
            if (!isValidAge(dom.value)) {
                // reset model value to an _unset_ state - e.g. null
                model.value=null;
                // attach error
                if (!dom.errors) dom.errors=[];
                dom.errors.push({
                    name:"InvalidAge",
                    message:"Invalid age: "+dom.value
                });
            }
        }
    }

Sub-template calls

Template is code – and as such developers need to be able to organize it in different parts, and libraries. As as corollary, it means that templates should be able to call sub-templates, and pass context-specific arguments – e.g.

    # template main(data)
        <div class="abc">
        # for (var i=0, sz=data.items.length; sz>i; i++)
            Beginning of item {i+1}
            # insert itemBlock(data.items[i],i+1)
            End of item {i+1}
        # /for
        </div>
    # /template

    # template itemBlock(item, index)
        <div class="item">
            {index}. {item.name}
        </div>
    # /template

I think it could be interesting as well to be able to pass templates as template arguments (as we frequently do in JavaScript with functions).

Let’s consider as an example an expandable section utility – that expands / collapses a sub-section when the user clicks on it. We may want for instance to define it as a separate template and store it in a template library – but of course we would like to keep as well the possibility to use a sub-templates to describe the section content. Here is how it could look like:

    # template main(data)
        # foreach (person in data.team) 
            # insert expandableBlock(person, person.firstName, tplContent)
        # /foreach
    # /template

    # template tplContent(person)
        <span class="persondesc">First name: {form.firstName} - Last name: {form.lastName}</span>
    # /template

    # template expandableBlock(data, title, contentTpl)
        # data.meta:expanded?=false  
        <span class="expTitle" onclick="{cb:toggle(data.meta:expanded)}">{title}</span>
        # if (data.meta:expanded) 
            # insert contentTpl(data)
        # /if
    # /template

The next natural step would be to be able to give an inline template definition (like a JavaScript anonymous function):

    # template main(data)
        # foreach (person in data.team) 
            # insert expandableBlock
                person, 
                person.firstName, 
                # template (person)
                    <span class="persondesc">First name: {form.firstName} - Last name: {form.lastName}</span>
                # /template
        # /foreach
    # /template

You may wonder as well what the data.meta:expanded expression means – it is actually a meta-data. Indeed it is often convenient to be able to create meta-data that can be attached to the data-model, and that could be ignored by the controllers. The expanded state of an expandable section is a very good example – same for the text value of a formatted field (cf. previous example: the data model stores the value with a specific format, while the UI may need to keep a temporarily invalid entry)

Simple event handlers

Without client-side templates, the generally-agreed good practice is to consider the DOM as semantic – which naturally imposes, among other rules, to remove inline styles and event-handlers from the DOM. One of the obvious benefit is that the page is more easily maintainable as one doesn’t need to change the code that generates the DOM (which is generally implemented with a server-side technology) to change the page behaviour (JavaScript) or layout (CSS).

With client-side templates, it is the data model that is generated by a server-side technology, and as such it make sense to consider it as the semantic part of the application (cf. MVC pattern family). As the template is code, it is more connected to the JavaScript layer, than to the DOM or to the CSS. This is why I consider it natural to re-introduce event handlers in the template syntax. The main benefits are that:

  • event-handler declaration become very simple and natural
  • we eliminate the need to write special code on top of the template to connect the DOM event handlers
  • but because of the very special nature of client-side templates, it can pass real data objects as event-handler arguments (on the contrary to html event handlers that can only pass basic types such as strings or integers) – e.g.:
    # template main(todos, controller)
        <div class="abc">
            <ul class="unstyled">
            # foreach (todo in todos)
                <li>
                    <input id="cb_{todo_key}" type="checkbox" value="{todo.done}" 
                        onchange="{cb:controller.toggle(todo)}">
                    # if (!item.isSelected)
                        // display the todo description as readonly text attached to the checkbox
                        <label for="cb_{todo_key}" class="done-{todo.done}">{todo.text}</label>
                    # else
                        // display a text field to modify the todo description
                        <input type="text" size="30" value="{todo.textTmp}"/>
                        <input class="btn" type="button" value="save" onclick="{cb:controller.save(todo)}"/>
                    # /if
                </li>
            # /foreach
            </ul>
        </div>
    # /template

    /*...*/

    MyController.prototype= {
        select:function(todo) {
            todo.isSelected=!todo.isSelected; // object.observe will automatically trigger the template refresh
        },
        save:function(todo) {
            todo.text=todo.textTmp;
            todo.isSelected=false;
        }
    }

This callback syntax offers 2 interesting features:

  • first, you can give a scope to your callback (e.g. controller in this example)
  • second, you can pass real objects as arguments (e.g. todo)

Note: I used the cb: prefix to make it clear that the syntax describes a callback and must not be interpreted as a JS function call
Note 2: Don’t misinterpret what I said about semantic HTML – I do believe that generating semantic HTML out of a template is THE good practice. Simply, because of the client-side nature of the template engine, event-handler should IMO be directly added through the templates (they will be added to the DOM anyway)

Widgets / Component libraries

When building rich or large applications, the need to share and externalize some pieces of the User Interface becomes crucial. One of the great benefit of templates is that they offer a natural possibility for an application to create its own set of widgets (e.g. auto-complete field or datepicker) – or larger components (e.g. a shopping basket component). Simple widgets can be implemented as shared sub-templates (cf. above), but advanced widgets usually require a specific data model and controller (and template, CSS, language resources, general configurations, etc).

While the complete description of the widgets / components is not in the scope of the template engine, I think the template syntax should support a notion of component library (by analogy to the JSP tag libraries). Some of the key features that should be supported are:

  • a notion of library name (e.g. through a global object / prefix)
  • the possibility to pass reach sets of arguments
  • the possibility to use data-binding or event-handlers for each of these arguments

Here is a possible example of what could be a widget / component call:

    var mylib = require("the_greatest");

    # template main(data,controller)
        Lorem ipsum dolor sit amet
        <div class="abc def">
            # mylib:selectbox({options:data.countryList, label:"Select a country", value:data.form.country>>checkCountry})
            // # mylib:selectox would be a shortcut to # insert mylib.selectbox()

            # mylib:datepicker({    id: "dp", 
                                    label: "Date: ",
                                    mandatory: true,
                                    calendarFirstDayOfWeek: 0,  // sunday
                                    calendarNumberOfUnits: 3,   // 3 months
                                    value: data.form.searchDate,
                                    calendarTemplate: mycustomTemplate, // to use another template than the one provided by the library
                                    onchange: cb:controller.checkDateConsistency() })

            # mylib.simpleContainer({id:"xyz"})
                <span> some content here... </span>
            # /mylib.simpleContainer
        </div>
    # /template

Note: I chose a JSON-based syntax instead of XML as it allows passing real objects as arguments (cf. options attribute). IMHO it also allows for better readability vs XML…
Note 2: Widget rendering logic should of course be implemented through templates – but it is a wider topic. If time permits, I will try to write another post on this topic in the coming months…

Internationalization / Localization

It is difficult to talk about User Interface without mentioning i18n / l10n. The fact is that with a template engine this is rather simple(r), provided that the template syntax supports multiple context objects. In the syntax I used throughout my examples, this would translate either through a new template argument or through a global (or component-scoped) variable:

    # template hello(person, lang)
        {lang.hello} {person.name}
    # /template

Sometimes we need as well to use special formatting patterns:

    # template hello(person)
        <div class="hellomsg">
            {format(lang.hello, person.title, person.firstName, person.lastName)}
            // format is a simple JS function performing some RegExp-based changes on the language-specific pattern
        </div>
    # /template

Visual transitions and dynamic CSS classes

Transition effects are key features of rich UIs – and as such should be well supported by the template technology. I can see 2 sorts of animations:

  • animations that can be applied on the DOM when a data-update event occurs (e.g. entrance, highlight or motion paths animations). A typical use case is a piece of text that should be highlithed during a few seconds when it changes.
  • animations that require to create 2 fragments of the same template in order to run entrance / exit animations. There are lots of use cases in this category:
    – page swipe
    – image carousels
    – or like in the following example: a read-only section that would become editable when a button is clicked, where fade-out, fade-in effects could be implemented:
    # template personalDetails(data, controller)
        <div>
        # if (!data.editMode)
            <div class="abc readonly fade in">
                // the following animations should be attached to the container div
                // "fade out" css will be set when the div should be removed 
                // the template engine should wait for the animation end before removing it from the DOM
                # @class.replace("in","out","ondelete") 

                First name: {form.firstName}<br/>
                Last name: {form.lastName}<br/>
                <input class="btn" type="button" value="edit" onclick="{cb:controller.edit()}"/>
            </div>
        # else
            // in edit mode - let's display the form
            <div class="abc edit fade in">
                # @class.replace("in","out","ondelete")
                # let form=data.form // form variable attached to the container div context
                First name: <input type="text" size="30" value="{form.firstName}"/><br/>
                Last name: <input type="text" size="30" value="{form.lastName}"/><br/>
                <input class="btn" type="button" value="save" onclick="{cb:controller.submit()}"/>
            </div>
        # /if
        </div>
    # /template

In the general case, it may be a good idea to give developers the possibility to trigger animations through custom events, raised by custom JS functions plugged on the data-model object-observe/ChangeSummary stack (Anyway, these are just first thoughts on this topic…)

Apart from transitions, a very common use-case is also to add or change multiple CSS classes for a given element, depending on the data-model state (cf. angular ng-class attribute).

    # template foo(item)
        <div class="item">
            # @class.add(item.selected? "selected" : "")
            # @class.add(item.disabled? "off" : "on")
            {item.title}: {item.description}
        </div>
    # /template

Of course, the @ prefix could be also used to specify other attributes (instead of using an inline expression):

    # template comment(item)
        <textarea name="comment">
            # if (item.checkSize)
                # @maxlength=item.maxsize // equivalent to maxlength="{item.maxsize}"
                # @class.add("formatted input")
            # /if
            {item.comment}
        </div>
    # /template

Modular architecture: CSS and JS scoping, dependency management, etc

As soon as we start implementing large web applications we see the need to split it into smaller independent components – such as widgets or application modules as mentioned earlier. The problem is that most HTML technologies have not been thought for componentization. As an example, even using and sharing a simple JavaScript file require conventions (or frameworks) as otherwise the file is likely to pollute the global page namespace, and consequently may generate unexpected side-effects resulting from variable collisions. If this is rather simple to solve for JavaScript (e.g. through namespace techniques or JS module frameworks), it becomes more complex with HTML DOM elements and CSS classes – i.e. developers don’t expect CSSs defined for a given component to alter the display of the entire application; similarly, sub-components should not be necessarily allowed to access the DOM of their container element, and reciprocally…

Now, you might be thinking: what is the point with client-side templating? Indeed, it is not the template technology that should define the componentization strategy. However it should provide some features to enable it, such as the possibilities to:

  • load template dynamically (e.g. through XHR)
  • bundle all component resources together (templates, JavaScript, CSS, etc)
  • support scoping / namespacing for each of the component artifacts (JavaScript, DOM, CSS…). As far as the DOM is concerned, it means for instance supporting the possibility to transparently transform each html id used in the template into unique ids (necessary when multiple template instances are used in the same DOM)
  • support the integration with some kind of dependency manager (cf. require js or noder for JavaScript modules)

Security and HTML escaping

I cannot terminate this article without a quick note on security: the biggest threat for template technologies is that they can be the fast track to code injection if proper escaping is not implemented. Consider for instance the following template:

# template hello(person)
    <h1> Hello {person.title} {person.name} </h1>
# /template

If person.name contains some malicious code (e.g. a script tag), then it will be interpreted by all the users that access this piece of data (that can be stored in the application DB). This is why it should systematically HTML-escape its values by default. Having said that, HTML-escape algorithm can be rater complex in the general case (cf. this interesting article on the topic), but it becomes much simpler when the template engine interprets the HTML syntax and forces the usage of double-quotes for HTML attributes (in this case escaping <, >, & and ” can be enough!).

Fast initial rendering and SEO

To complete the icing on the cake, the template engine should ideally be able to plug itself on an existing DOM that would have been generated on the server-side (as you can guess, with a server-side engine supporting the same template syntax!).
The main benefits are twofold:

  • faster rendering time for the first page display (cf. twitter performance improvements)
  • easy support of Search Engine Optimization constraints (i.e. the page directly contains the page content, so that non-JavaScript- or template- enabled crawlers can still index the page) – which solves one of the most painful aspects of client-side UI rendering frameworks

Conclusion

Well, if you managed reading up to here, I hope this article convinced you of the interest of considering templates as functions.

Some of you may also wonder how the previous examples could be implemented in a real template engine. My current favorite option would be to implement the solution in 2 parts:

  • a pre-processor that would parse the previous syntax embedded into JavaScript files and that would transform each template into a JavaScript function
  • a run-time library that would contain the necessary code to run templates and manage data-bindings

The benefits of this approach would be that

  • the size of the pre-processor would not impact the application performance as it won’t be downloaded at run-time
  • advanced syntax, parsing logic and error management could be implemented in the preprocessor
  • the template JS function could be integrated into JavaScript modules, so that any JS dependency manager could be used to bundle and download the templates (e.g. require js or noder)

On top of this I would recommend to deliver the template engine as an independent library, without any strong dependency to any MVC or JS dependency-management framework. The last challenge will be of course to keep the run-time size as low as possible!

Having said that, there is no clear plan on aria templates to go in this direction yet. But we may start experimenting soon(?). If you are interested, or if you wish to participate, feel free to contact us – and stay tuned!

[update - January 18th, 2013]: the template engine described in this article is being implemented here

2 responses on “Key features for client-side templates

  1. Josip Team Member
    on 28 May 2013, 10:16 am

    Great article!!

  2. David R Wallace Team Member
    11:41 pm

    Interesting seeing your approach and nice to see an attempt to clarify and nail down the elements fundamental to rendering engines. I’ve been going through this process over the past couple years in development of custom rendering solutions for my company. Many may suggest it is unreasonable to create a custom rendering framework when there are several refined and ready to go solutions out there. They’re probably right, but I don’t care. I decided no more, after years of adopting one “framework of the day” after another, and without exception running into brick walls and in the end, weighted down with an extra big blob of under-the-hood code to support the generic-ness needed for broader public consumption.

    I am with you on most of the aspects you’ve described, but it is interesting how different one’s approach can be, while satisfying the same requirements.

    The main disagreement I have with the approach you outline, is the HTML-structured format of the template. This requires two things I wish to avoid: custom syntax and/or pre-compiler. (see rendering engine for the rendering engine). It seems a little redundant to write the components in the same form that the engine is there to output – seems like it has to sort of be unhindered, then cooked, then re-rendered. It is mainly for these reasons that I prefer not to mix and match coding formats/languages. All my components are in form of singleton hashmaps, packaged with basic function executor so maps can have any type of function. Like with your approach, the map can reference any one of its parts, and can send part maps as parameters to itself etc. One of my goals is to reduce the amount of looping and number of control structures as possible. It is super fast because the output and logic are assembled 80% through direct reference – sort of like how one can use joins to control database output instead of looping through a bunch of conditionals. The other thing I like about this pattern, is that because the format allows for effortless combining of meta info from database, with modules from elsewhere, with zero conversion because its all JSON; So far, I’ve ended up with all javascript solution, with one engine of parts nearly identical in structure; with little to no re-doubling of functions or template parts.
    Okay, didn’t mean to write another whole article on the subject as a response, so ..
    Thank you for the article and your thoughts on the subject,
    Dave.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>