Javascript-форум (https://javascript.ru/forum/)
-   Ваши сайты и скрипты (https://javascript.ru/forum/project/)
-   -   Snakeskin (https://javascript.ru/forum/project/35057-snakeskin.html)

kobezzza 26.12.2013 11:31

Цитата:

Сообщение от nerv_ (Сообщение 289305)
Здорово, но большинство опций я вряд ли буду использовать. Это уже для продвинутых "юзеров" :)

Ну в первую очередь это нужно мне:)

monolithed 27.12.2013 00:59

В последнее время все больше склоняюсь к выбору шаблонизатора с трансляцией на клиенте.

Кстати вот очень клевая штука:
http://www.ractivejs.org/

kobezzza 07.01.2014 18:31

Фух, почти закончил работу над новой версией, вышло дольше чем думал. На этой недели закончу, но уже предлагаю поиграться с бетой и заодно потестить : http://jsfiddle.net/NAPWB/6/.

С функциональной стороны сделано всё, что хотел, и даже больше, однако ещё нужно написать новые тесты, обновить доку и т.д.

Ну а теперь по порядку. Изначально данный апдейт планировался как эволюционное развитие ветки 2.x, однако в ходе разработки, стало ясно, что необходимы некоторые принципиальные изменения, которые повлекут за собой несовместимость с предыдущей версией, поэтому новая версия выйдет как 3.0.0.

Что изменилось по сравнению с 2.x:

1) Реализована блочная область видимости переменных вместо единой шаблонной, т.е.

{template foo()}
    {if 1}
        {var a = 1}
        {a} /// 1
    {/}

    {a} /// error, a is not defined
{/}


Отмечу, что данное нововведение распространяется именно на переменные, т.е. константы работают также, как и раньше.

2) Переосмыслена и переделана работа с пробельными символами: теперь любой пробельный символ (будь то табуляция или переход строки) трактуются как пробел, однако смежные пробельные символы схлопываются в один, т.е.

{template foo()}
/// перевод строки даст пробел
<div
class="foo">
{/}


Также введена новая директива &, которая декларирует, что все пробельные символы после этой директивы до любого не пробельного символа будут вырезаться, т.е.:

{template foo()}
   Привет{&}                 Мир! /// получится ПриветМир!
{/}


3) Директивы cut и save были убраны, а их функционал частично заменила новая директива placeholder. Эта директива имеет одинаковый синтаксис с директивой template, однако, в отличии от template, placeholder существует только на этапе трансляции, т.е.

{placeholder foo()}
   foobar
{/}


foo(); // error


Директива может участвовать в цепи наследований также, как и template.

4) Добавлен новый возможный аргумент для директив forEach и forIn (forIn отличается от forEach тем, что всегда итерирует объект, как for (key in data), причём без проверки на hasOwnProperty). Теперь порядок аргументов для forEach такой:

Для массивов:
*) Ссылка на элемент массива;
*) Индекс массива;
*) Ссылка на итерируемый массив;
*) Является ли первым;
*) Является ли последним;
*) Длина массива.

Для объектов:
*) Ссылка на свойство;
*) Ключ свойства;
*) Ссылка на итерируемый объект;
*) Номер итерации;
*) Является ли первым;
*) Является ли последним;
*) Длина объекта.

Для forIn аргументы такие же, как и у forEach для объектов. Кстати, теперь директивы forEach и forIn разворачиваются в циклы на этапе трансляции, что позволило увеличить скорость скомпилированных шаблонов, а также возможность использования новых директив break и continue.

5) Для директивы data изменено сокращение, теперь это =, т.е.
{template foo()}
   {= foo, bar}
{/}


Старое сокращение {{}} теперь используется новой директивой decl, которая вставляет текст, так как он был написан вместе со скобками директивы, т.е.:
{template foo()}
   {{foo}} /// даст {{foo}}
{/}


Также, как и в data, в decl можно прокидывать переменные из шаблона, с помощью синтаксиса ${}. Новая директива decl создана для удобного использования библиотек, которые осуществляют data binding (вроде http://www.ractivejs.org/).

6)
Костыль для console был удалён, теперь нужно использовать директиву void
{template foo()}
   {void console.log(1)}
   /// или так
   {?console.log(1)}
{/}



На этом ломающие изменения заканчиваются. Основные нововведения:


1)
Добавлена директива super, которая осуществляет вставку тела родительского блока или прототипа:

{template base()}
   <head>
       {block scripts}
           <script src="../1.js"></script>
       {/}
   </head/>
{/}

{template child() extends base}
   {block scripts}
       {super}
       <script src="../2.js"></script>
   {/}
{/}


2) Прототипы теперь поддерживают параметры и рекурсию, а также новую директиву return:
{template foo()}
   {proto bar(i)}
      {i}

      {if i === 2}
           {return}
      {/}

      {if i}
          {apply bar(--i)}
      {/}
   {/}

   {apply bar(4)} /// 4 3 2
{/}


3) Прототипы теперь можно выносить за пределы шаблона, перед декларацией
{proto foo->bar}
    1
{/}

{template foo()}
   {apply bar}
{/}


4)
Добавлена поддержка jsDoc
/**
 * Данный комментарий будет в скомпилированном JS
 * @return {string}
 */
{template foo()}
   1
{/}


5) Директива var теперь имеет сокращение : и поддерживает множественную декларацию
{template foo()}
   {:a = 1}
   {var b = 2, e = 3}
{/}


6) Новые директивы switch case (имеет сокращение >) default

{template foo()}
   {switch 1}
      {case 1} foo {/}
      {> 2} foo2 {/}
      {default} foo3 {/}
   {/}
{/}


7) Новые директивы try catch finally

{template foo()}
   {try}
       {void dddd()}
   {catch err}
        {err}
   {finally}
        bar!!!
   {/}
{/}


8) Новые директивы break и continue. Могут использоваться внутри forEach, forIn, for, while, do, repeat.
9) Для цикла repeat-until добавлен псевдоним do-while
10) Новая директива return. Может использоваться внутри прототипов или шаблона (в случае шаблона может принимать значение)

11) Новая директива attr для удобного задания атрибутов узлам в xml разметке:
{template foo()}
   <div {attr 'class', 'foo'} {attr -'bind', 'bar'}></div> /// class="foo" data-bind="bar"
{/}


12) Частично переписано АПИ добавления директив, в релизе будет иметь документацию, пример:

Snakeskin.addDirective(
	'if',

	{
		placement: 'template',
		notEmpty: true
	},

	function (command) {
		this.startDir();
		if (this.isSimpleOutput()) {
			this.save('if (' + this.prepareOutput(command, true) + ') {');
		}
	}
);

Snakeskin.addDirective(
	'else',

	{
		placement: 'template'
	},

	function () {
		if (this.structure.name !== 'if') {
			throw this.error('Directive "' + this.name + '" can only be used with a "if"');
		}

		if (this.isSimpleOutput()) {
			this.save('} else {');
		}
	}
);


13) Увеличена скорость работы транслятора и исправлено множество ошибок
14) Сильно увеличена скорость работы в "живом" режиме в браузере
15) Очень сильно доработана обработка ошибок
16) 100% code review и рефакторинг + теперь исходный код переписан на ECMAScript 6 :)

Вроде всё :)

kobezzza 07.01.2014 22:15

Ради интереса сравнил скорость рендеринга с другими шаблонными движками... и каково было моё удивление, что Snakeskin занял первое место, обойдя даже самые примитивные шаблонки http://jsperf.com/templates/2 я почему то был уверен, что результат должен быть другим

monolithed 07.01.2014 22:41

Цитата:

Сообщение от kobezzza
Реализована блочная область видимости переменных вместо единой шаблонной, т.е.

Хм. разве не для этого придумали let?
Цитата:

Сообщение от kobezzza
Также введена новая директива &, которая декларирует, что все пробельные символы после этой директивы до любого не пробельного символа будут вырезаться, т.е.

Очень сомнительная фича ;)

Цитата:

Сообщение от kobezzza
6) Костыль для console был удалён, теперь нужно использовать директиву void

А почему просто не дать писать console.log?
Цитата:

Сообщение от kobezzza
Директива var теперь имеет сокращение : и поддерживает множественную декларацию

Цитата:

Сообщение от kobezzza
8) Новые директивы break и continue. Могут использоваться внутри forEach

Цитата:

Сообщение от kobezzza
9) Для цикла repeat-until добавлен псевдоним do-while

Цитата:

Сообщение от kobezzza
Новые директивы switch case (имеет сокращение >) default

Цитата:

Сообщение от kobezzza
7) Новые директивы try catch finally

Почему просто не писать так:

{template}
<script>
  ....
</script>
{/template}
?

Зачем усложнять то?

Цитата:

Сообщение от kobezzza
Новые директивы switch case (имеет сокращение >) default

Не знаю насчет такого синтаксиса, но во многих нормальных языках типа Haskell можно писать так:

switch text
      | "one"        => 1
      | "two"        => 2
      |              => 0


Ну или как LiveScript:

switch text
      case "one"  
            then 1
      case "two" 
             then 2
      case "three", "four"  
             then "3-4"
      default  
             then 0

monolithed 07.01.2014 22:45

Цитата:

Сообщение от kobezzza
самые примитивные шаблонк

HandlebarsJS забыл :)

Цитата:

Сообщение от kobezzza
необходимы некоторые принципиальные изменения

Планируешь будет data-binding?
Просто в современной разботке single-page приложений перерисовывать весть блок не очень гуд, особенно если в этом блоке сотни и тысячи элементов.

kobezzza 07.01.2014 22:49

Цитата:

Сообщение от monolithed (Сообщение 290926)
HandlebarsJS забыл :)

Он чёто не завёлся, потом сделаю более полный и нормальный тест, сёня уже сил нет.

Цитата:

Сообщение от monolithed (Сообщение 290926)
Планируешь будет data-binding?

Нет, Snakeskin - это шаблонный движок а не блендер из ХЗ чего, я просто сделал для него удобную синтаксическую основу. Т.е. дата-биндинг должен делаться отдельной либой.

kobezzza 07.01.2014 22:54

Цитата:

Сообщение от monolithed (Сообщение 290924)
Хм. разве не для этого придумали let?

Я бы с радостью юзал let-ы если бы они везде работали.

Цитата:

Сообщение от monolithed (Сообщение 290924)
Очень сомнительная фича ;)

/// Срежет не нужный пробел
<p>{&}
   1
   2
</p>


Цитата:

Сообщение от monolithed (Сообщение 290924)
А почему просто не дать писать console.log?

Раньше так и было, но это было хаком. Для таких операций есть директива void, её и нужно юзать.


Цитата:

Сообщение от monolithed (Сообщение 290924)
Почему просто не писать так:

{template}
<script>
  ....
</script>
{/template}
?

Зачем усложнять то?

Тут можно долго спорить.


Цитата:

Сообщение от monolithed (Сообщение 290924)
Не знаю насчет такого синтаксиса, но во многих нормальных языках типа Haskell можно писать так:

switch text
      | "one"        => 1
      | "two"        => 2
      |                 => 0


Ну или как LiveScript:

switch text
      case "one"  
            then 1
      case "two" 
             then 2
      case "three", "four"  
             then "3-4"
      default  
             then 0

Ну у меня не язык программирования, а препроцессор шаблонов.

monolithed 07.01.2014 23:04

Цитата:

Сообщение от kobezzza
Ну у меня не язык программирования, а препроцессор шаблонов.

Тем не менее, ты вводишь новый синтаксис :)

Если уж вводить синтаксический сахар, то лично мне кажется нужно отталкиваться от существующих решений.
Вот пример из того же Haskell:
f x = 
    case x of
        0 -> "one"
        1 -> "two"
        _ -> 0 - x


Цитата:

Сообщение от kobezzza
Я бы с радостью юзал let-ы еслибы они везде работали.

А так ты вносишь неясность в голову JS-программистов.

Цитата:

Сообщение от kobezzza
/// Срежет не нужный пробел

Ни разу не требовалось.

Цитата:

Сообщение от kobezzza
Тут можно долго спорить

А в чем спор будет заключаться?
Вот к примеру в fest нет ничего лишнего, только основные инструкции и возможность писать произвольный JS код:

<fest:script>
var obj = {"foo": "bar"};
</fest:script>

<fest:each iterate="obj" index="i">
     <fest:value>obj[i]</fest:value>
</fest:each>


Пока я вижу в этом только плюсы, т.к. не нужно придумывать новые инструкции и усложнять парсинг.

Цитата:

Сообщение от kobezzza
Нет, Snakeskin - это шаблонный движок а не блендер из ХЗ чего, я просто сделал для него удобную синтаксическую основу.

Ну как сказать,
Цитата:

Сообщение от monolithed
Просто в современной разботке single-page приложений перерисовывать весть блок не очень гуд, особенно если в этом блоке сотни и тысячи элементов.


kobezzza 07.01.2014 23:15

Цитата:

Сообщение от monolithed (Сообщение 290933)
Тем не менее, ты вводишь новый синтаксис :)

За основу я взял синтаксис из Google Closure Templates и Django Templates.

Цитата:

Сообщение от monolithed (Сообщение 290933)
Если уж вводить синтаксический сахар, то лично мне кажется нужно отталкиваться от существующих решений.
Вот пример из того же Haskell:
f x = 
    case x of
        0 -> "one"
        1 -> "two"
        _ -> 0 - x

Я отталкиваюсь от грамматики, которая была изначально задана.

Цитата:

Сообщение от monolithed (Сообщение 290933)
А так ты вносишь неясность в голову JS-программистов.

Не думаю.

Цитата:

Сообщение от monolithed (Сообщение 290933)
Ни разу не требовалось.

А мне требовалось, а т.к. пишу я для себя в первую очередь - вот и добавил.

Цитата:

Сообщение от monolithed (Сообщение 290933)
А в чем спор будет заключаться?
Вот к примеру в fest нет ничего лишнего, только основные инструкции и возможность писать произвольный JS код:

Мне нравится синтаксис Closure Templates, Dust и т.д.

Цитата:

Сообщение от monolithed (Сообщение 290933)
Просто в современной разботке single-page приложений перерисовывать весть блок не очень гуд, особенно если в этом блоке сотни и тысячи элементов.

Ещё раз: дата-биндинг - это задача отдельный либы, которая использует шаблонизатор.


Часовой пояс GMT +3, время: 15:51.