STAN — самый короткий шаблонный движок

в 0:32, , рубрики: html, javascript, south park, template, грибы, Программирование, метки:

image

Холодным Апрельским днем когда на Урале еще не растаял снег. Смеркалось. Я игрался с микро-шаблонами. К примеру: ejohn.org/blog/javascript-micro-templating/ Они все были сверхпроизводительны на пcевдо тестах, но в тоже время в них отсутствовал хоть какой либо более или менее серьезный функционал.

Последней каплей стало то что я пропустил js1k. One thing led to another. И в голову мне пришла интересная идея. Почему бы максимально не использовать возможности JS? Использовать синтаксис JS в шаблоне ( что позволит с помощью JS движка парсить шаблоны ) и использовать все возможности JS.

И получился шаблонный движок с довольно простым синтаксисом:

[TAG] raw( data: String ) | variable [TAG] 
[TAG].b
[TAG].e
[TAG]
raw( data: String )

Что выглядит приблизительно так:

function _template() {
    div.b;
    span.context.value.span;
    span.raw(11).span;
    div.e;
    hr;
    raw('plain text')
}
div.b -> открывающийся тэг -> <div>
div.e -> закрывающийся тэг  -> </div>

div.context.value.div -> <div>{{ context.value }}</div>

hr -> самозакрывающийся тэг -> <hr/>

Получается своего рода DSL.

И какого размера код?

30 строчек кода :) Я уж не говорю про минифицированную версию.

Пример?

// Данные - на самом деле в шаблон можно передать 
// любой JS обьект ( включая примитивы )
var data = [
    { name: 'STAN' },
    { name: 'Ai_boy' },
    { name: 'IceFrog' }
];

// Главный шаблон
function _template(){
    
    // Через [ ] можно передать атрибуты нашему XML тегу 
    h1['class="head"'].raw('List of names').h1;

    for (var i = 0; i < context.length; i++) {
        // вызываем подшаблон
        partial(_item, context[i]);
    }
}

// Partial - подшаблон
function _item(){
    b[args({style: 'color: blue', class: 'test'})].raw("Name:").b;
    div.context.name.div;
    hr;
}

// Написание кастомных helper функций никогда
// небыло настолько простым - просто пишем js
function args(obj){ 
  var result = '';
  for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
      result += key + '="' + obj[key] + '" ';
    }
  }
  return result;
}

document.body.innerHTML = STAN.run(STAN.compile(_template), data);

Как начать?

Можно зайти на сайт и поиграться в Sandbox
aiboy.github.io/STAN/sandbox.html

Либо зайти на GitHub страницу и следовать инструкции в README.md
github.com/aiboy/STAN
(использовать шаблонизатор можно как в браузере так и в Node.js )

В чем плюс?

Главных приемущества ровно четыре:

1) Полная поддержка JS синтаксиса и всех его возможностей ( CoffeeScript, ClosureScript, TypeScript… ect )

2) Доступ к DOM в момент рендеринга шаблона.

3) Полная поддержка всех JS библиотек внутри шаблона ( lodash, underscore, jquery… ect )

4) Поддержка шаблонов в любом текстовом редакторе — ибо они на самом деле представляют из себя чистый JS синтаксис

А скорость?

jsperf.com/stan-speed-test
image

Скорость «скомпилированного» шаблона ( который потом вручную или автоматически превращен в обычный js файл ) приблизительно равна скорости JavaScript :) Что весьма и весьма не плохо. Если динамически компилировать шаблоны то скорости увы не такие большие.

Почему не Zen Coding?

Потому что Zen Coding не возможно выразить в рамках JS синтаксиса — тоесть Zen Coding — не может быть валидным JS.

Это шутка?

Несмотря на безумность/глупость ( нужное подчеркнуть ) идеи. Все весьма и весьма серьезно. Проект будет развиваться. Обрастать тестами, более правильным синтаксисом и многими другими плюшками. Заходите на GitHub страничку — оставляйте ваши пожелания, найденные баги и все прочее.

PS: На самом деле я немного кревлю душой когда пишу что данный шаблонизатор состоит всего из 30 строк. Если честно отформатировать код то получится строк 40-50. Но для меня это больше психологический барьер которого я стараюсь придерживаться.

PPS: буду рад любым замечаниям по поводу «корректности и грамотности заметки» ( но будет лучше если все это будет написанно в личку )

Автор: Ai_boy

Источник

Поделиться

* - обязательные к заполнению поля