Templating System for Node.JS.
Допилил. Наконец-то.
В общем, тем кто ещё не знает, хочу рассказать про свой шаблонизатор для NodeJS. Исходники: https://github.com/B-Vladi/TSN Основные характеристики:
Некоторые моменты:
На данный момент нет такого же классического XML-шаблонизатора для ноды. Да и XML-шаблонизаторов я знаю только 2 - Fest и TSN. Убедительная просьба: не разводить holy war на тему - "Синтаксис XML - говно, юзай Dust". |
Поставлю 12 бубунут под кедами прикручу туда nodeJS и попробую сие творение ;)
|
Gozar, не обязательно, сие заводится даже из-под окон :yes:
|
Довёл до ума документацию: разбил по wiki-страницам, описал остальные моменты. Вникнуть в суть стало теперь намного проще :)
Осталось только написать мануал по API создания тегов. |
:blink: Вышла новая версия - 2.0.3.
Что изменилось: 1. Добавлен тег set, для изменения значения ранее созданной переменной (тег var). Работает точно по такому же принципу, как и тег var. 2. Добавлен атрибут item в теги for и each, что бы не приходилось явно сохранять текущий элемент массива/значение текущего свойства в переменную. |
Я понимаю, что всем похуй, но всё же...
:blink: Вышла новая версия - 2.1.0 Что изменилось: 1. Выпилил тег set за ненадобностью ;) 2. Теперь переменные из внешнего шаблона не доступны в подключаемых, дабы не прострелить себе ногу. 3. Добавлен метод extend, для расширения набора тегов из кода. 4. Пойманы и наказаны несколько багов. 5. Расширилось API тегов. Приведу пример шаблона: page.xml: <tsn:root xmlns:tsn="TSN"> <!-- Создаем скрипт для хедера --> <!-- Сначала сгенерируем конечный результат и сохраним в переменную --> <tsn:var name="header"> <script type="text/javascript"> //<![CDATA[ console.log(); // ]]> </script> </tsn:var> <!-- А при вызове шаблона просто будем возвращать результат --> <tsn:template name="header"> <tsn:echo text="_var.header" /> </tsn:template> <!-- Контент страницы --> <tsn:template name="body"> <div>Body</div> </tsn:template> <!-- Подключаем базовый шаблон --> <tsn:include src="base.xml" context="this.globalData" /> </tsn:root> Файл с базовой разметкой base.xml: <html xmlns="http://www.w3.org/1999/xhtml"> <head> <link href="base.css" type="text/css" rel="stylesheet"/> <!-- Здесь будет выводиться стили для конкретной страницы --> <tsn:include name="header" /> </head> <body> <!-- Вставляем навигацию с передачей необходимых данных --> <tsn:include src="common/navigation.xml" context="this.navigation" /> <!-- Вставляем контент, который был определён ранее и унаследован здесь --> <tsn:include name="body" /> <!-- Вставляем футер с передачей необходимых данных --> <tsn:include src="footer.xml" context="this.footer" /> </body> </html> Вроде всё логично и понятно, как думаете? |
Цитата:
|
Цитата:
|
Цитата:
:blink: Вышла новая версия - 2.1.1 Что изменилось: 1. Теперь в теге include абсолютные пути в атрибуте src начинаются с TSN.config.templateRoot. Относительные пути начинаются с папки текущего шаблона или от TSN.config.templateRoot, если текущий шаблон компилируется методом TSN.compile. 2. Пофикшен мелкий баг. Более серьёзных правок не предполагается, все основные моменты, которые хотел реализовать - реализовал. Если пользователи будут предлагать достойные изменения - буду впиливать. |
Цитата:
И между прочем я тебе помогал с тестированием ) |
ну и добавлю если сравнивать с шаблонизаторами под другие платформы то для шаблонизаторов на nodejs нужно учитывать потери на передачу данных. Как минимум это: формирование json, сетевые издержки и парсинг json в nodejs.
|
Цитата:
Цитата:
Цитата:
Цитата:
Цитата:
|
:blink: Вышла новая версия - 2.2.1
Что изменилось: 1. Добавлена возможность записи в поток! Спасибо vflash за наводку, как-то я забыл про это совсем. Для этого нужно просто передать объект Stream вторым параметром при рендеринге: template.call(data, response); При этом функция по прежнему возвращает результат рендеринга. Если ещё что смущает, не нравится или не хватает - пишите :write: |
Через недельку наверно понадобится твой шаблонизатор, так что если что, буду терраризировать вопросами на работе:)
|
Цитата:
|
Мне monolithed подкинул одну мысль: сделать компиляцию файлов пачкой.
Хочу спросить у сообщества - как вы это видите? Пока есть такие варианты: 1. Выделить отдельный метод, в который будет передаваться массив/хеш шаблонов. 2. Реализовать рекурсивный обход директории и компилировать в ней все (?) файлы 3. Не делать. |
B~Vladi, Вы же знаете, что рекурсия - это плохо, особенно когда нужна скорость. Я за второй метод, но его вариацию без рекурсии.
|
Цитата:
Важно, что бы было удобно использовать. |
какая разница в использовании от метода сбора файлов? на выходе же всё равно один файл получится :)
хм, может, через Makefile ? и заодно там же поуказывать настройки сборки. |
Цитата:
Не один. При компиляции никаких файлов не создается. Шаблон из файла компилируется в JS-функцию, которую потом можно получить из кеша TSN.cache. |
Обновилась версия - 2.3.0
Основное изменение - добавлен тег else с атрибутом if ;) |
Добавил модуль в npm и в список модулей.
|
Перед выходом новой версии хочу провести небольшой эксперимент и попросить вашего участия в нем :)
Если вы потратите немного своего времени, я буду вам очень признателен :) Есть некие файлы шаблонов: page.xml: <?xml version="1.0" encoding="UTF-8"?> <tsn:root xmlns:tsn="TSN" xmlns="http://www.w3.org/1999/xhtml"> <tsn:data key="JSBlock"> <script type="text/javascript"> //<![CDATA[ alert('Page.'); //]]> </script> </tsn:data> <tsn:render file="service.xml" /> </tsn:root> service.xml: <?xml version="1.0" encoding="UTF-8"?> <tsn:root xmlns:tsn="TSN" xmlns="http://www.w3.org/1999/xhtml"> <tsn:data key="JSBlock" action="prepend"> <script type="text/javascript" src="&TSN.this.serviceName;.js"> </script> </tsn:data> <tsn:block name="JS" type="global"> <tsn:echo data="_data.JSBlock" /> </tsn:block> <tsn:block name="CSS" type="global"> <link rel="stylesheet" type="text/css" href="service.css" /> <tsn:if expr="_data.CSSBlock"> <tsn:echo data="_data.CSSBlock" /> </tsn:if> </tsn:block> <tsn:block name="content" type="default"> Page not found </tsn:block> <tsn:render file="base.xml" /> </tsn:root> base.xml: <?xml version="1.0" encoding="UTF-8"?> <tsn:root xmlns:tsn="TSN" xmlns="http://www.w3.org/1999/xhtml"> <tsn:render file="common.xml" /> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html> <head> <tsn:render block="CSS" /> </head> <body> <tsn:render block="content" /> <tsn:render block="JS" /> </body> </html> </tsn:root> common.xml: <?xml version="1.0" encoding="UTF-8"?> <tsn:root xmlns:tsn="TSN" xmlns="http://www.w3.org/1999/xhtml"> <tsn:data key="JSBlock" action="prepend"> <script type="text/javascript" src="common.js" /> </tsn:data> <tsn:block name="content" type="default"> <tsn:render file="/404.xml" config="({ cache: false })" /> </tsn:block> </tsn:root> Вопрос: глядя на код шаблонов, можно ли, потратив несколько минут, вникнуть в суть происходящего. Прикинуть, что будет на выходе. Без документации. Дополнительный вопрос: какие моменты показались вам нелогичными/непонятными. |
Я понял более-менее, но не понял, зачем нужен элемент data, почему у него такое же значение атрибута key, как и name и элемента-блока, и что означает у него значение атрибута action - prepend.
|
Цитата:
Цитата:
Цитата:
|
Немного подправил пример, что бы не возникало лишних недопониманий.
|
Вот более полный пример: https://github.com/B-Vladi/TSN/tree/2.4.0/example
|
Для тех, кому интересно, предлагаю обсудить API.
Обновленный JSDoc в репозитории: https://github.com/B-Vladi/TSN/tree/2.4.0/jsdoc Для удобства выложил сюда: http://tsn.amxhost.ru |
UPD: небольшой upgrade.
|
Мне тут подкинули идею и я реализовал теги header и status. Хотя раньше это можно было сделать и в JS-выражениях.
Как пиздато самим с собой разговаривать |
Цитата:
А вообще я наблюдаю за развитием твоего проекта, пока не придумал конечно куда это внедрить. Но мысли некоторые навивают. |
Цитата:
Из последнего: закончил реализацию тега script, буквально пару часов назад. Пара примеров: <tsn:script> <[CDATA[ // Код выполняется в глобальной области видимости шаблона. // Созданные переменные будут доступны в других JS-выражениях и тегах script. var data = { key: 'value' }; ]]> </tsn:script> <tsn:echo data="data.key" /> Выведет: "value". Или так: <tsn:script type="local"> <[CDATA[ // Код выполняется в локальной области видимости анониймной функции. // Тег этого типа может выводить текстовые данные в результат через return: return 'Text'; ]]> </tsn:script> На выходе: "Text". Ещё есть атрибут context в теге типа local, работает так же как и в других тегах. Вообще раньше я был против подобных возможностей в шаблоне, но потом понял, что раз шаблон реализует view-логику, то такой тег необходим для написания костылей или упрощения преобразования данных. Как вариант, в нем можно создавать функции-модификаторы, что бы потом использовать в JS-выражениях в других шаблонах. |
Цитата:
|
Цитата:
|
В примере есть одно некрасивое решение с переопределением блока CONTENT. Сейчас, что бы обернуть существующий блок в разметку и заменить его, нужно изъебываться с сохранением в хранилище данных результат рендеринга блока. Для такой ситуации я реализовал новый тип блока wrapper:
<tsn:block name="CONTENT" type="wrapper"> <div class="service"> <tsn:render block="CONTENT" /> </div> </tsn:block> Этот блок сначала сохраняет глобальный блок с именем name как локальный, а затем заменяет глобальный блок собой. Это позволяет вызывать оригинальный блок CONTENT внутри блока типа wrapper, потому как локальные блоки имеют больший приоритет при использовании тега render. Если смотреть на код шаблона, не должно возникать двусмысленностей с именами блоков, если знать про тип wrapper. Как вам такое решение? Пока не пушил на гитхаб. |
B~Vladi,
вот сижу выбираю шаблонизатор какой нить, но нужен что бы работал c PHP а не NodeJS, есть идеи? Твой реально на PHP переписать? И как ты на это смотришь? |
Цитата:
Цитата:
Цитата:
Цитата:
|
Цитата:
Цитата:
|
Цитата:
|
Цитата:
|
Часовой пояс GMT +3, время: 10:24. |