Почему мы перешли на Marionette.js

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

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

Теперь, если подумать, в те времена разрабатывать было проще, из-за того, что все пользователи были одинаково ограничены аппаратной частью.

К несчастью (для разработчиков), ограничения, наложенные этой моделью, также полностью неприемлемы для конечных пользователей. Они хотят отзывчивое, быстрое, красивое ПО, что почти неосуществимо в условиях, когда любое небольшое действие ведет к запросу-ответу на удаленный сервер.

Эволюция веб интерфейсов


Вы можете увидеть похожую эволюцию в веб-разработке. Мы находимся в состоянии изменения парадигм, и чем дальше, тем сложнее будет приложениям написанным в старой парадигме. Зачем использовать то, что не отзывчиво и дает небольшую интерактивность, когда у нас есть альтернативы избавленные от этого?

UI архитектура это очень тяжелая проблема дизайна, и даже если большие компании годами вкладывали миллионы долларов в ее решение, у нас до сих пор даже близко нету “Одного правильного пути” чтобы сделать это. Много JavaScript “MVC” фреймворков (это почти такой же плохой термин как серверные MVC фреймворки) появились на протяжении последних лет и принципиально отличаются в том как применить идеи UI архитектуры последних 50 лет к вебу.

Выбирая фреймворк


Мы попробовали множество фреймворков, но для краткости, я опишу четыре наиболее популярных: Backbone, Ember, Knockout, и Angular.
Перед тем как начать, я хочу сказать что все это действительно потрясающие проекты имеющие заслуженную популярность. Нету такой вещи как “Серебряная пуля” в разработке, которая была бы хороша во всех ситуациях и проблемах, и каждый из этих фреймворков имеет сильные и слабые стороны.

Наша ситуация


У нас (приблизительно) 250 тысяч строк кода промышленного Rails приложения. Оно провело большую часть своей жизни следуя “Пути Rails”, и мы получили из этого множество уроков. В приложении прописано нереальное количество бизнес логики. Таким образом, масштабируемость и гибкость были двумя ключевыми критериями, которыми мы руководствовались при выборе фреймворка.

Ember.js


Исходя из документации и разговоров Yehuda Katz (wycats) о Ember.js, это в основном попытка сделать Rails на стороне клиента.
Ember самый амбициозный из доступных сейчас фреймворков и его сильные стороны очевидны. Он лишает вас возможности выбора в ряде случаев и это бывает достаточно удобно. В частности, мне нравится их подход к роутингу (Менеджер состояний / StateManager), мне кажется это гораздо лучше остальных реализаций.

Слабая сторона Ember — это результат его преимуществ; если вы не хотите идти по пути Ember — для вас наступают тяжелые времена. Если вы сталкиваетесь с проблемой, то имеете дело с чрезвычайно комплексным фреймворком, и, скорее всего, не сможете быстро решить проблему. Ember только достиг версии 1.0 и еще значительно изменится в ближайшие годы. С фреймворками которые имеют такой уровень присутствия в каждом аспекте вашего кода, обновление может стать тяжелым испытанием (у нас ушло больше года чтоб закончить апгрейд Rails до третьей версии).

Последней каплей для меня стало то, какой контроль Ember выполняет за вашей архитектурой. У нас достаточно навыков, чтобы делать собственный выбор, поэтому я считаю, что работа с тем что накладывает на нас столько ограничений это плохой выбор.

Angular.js


Angular использует подход согласно которому в HTML и JavaScript отсутствуют ключевые вещи делающие его более подходящими для создания сложных интерфейсов. В случае JavaScript, то что нужно — это наблюдаемые объекты. Для HTML недостающая часть это некая форма шаблонизации. Так как оба являются расширяемыми языками, то что делает Angular — это добавляет такие возможности.
Я большой фан Angular. Он предоставляет прозрачное разделение между представлениями и бизнес логикой, компонентную реализацию, совмещающую поведение и структуру — то, в чем действительно нуждается нынешний веб. Он также содержит внедрение зависимости (Dependency Injection framework), то, что многие разработчики считают излишним, но я думаю это хорошая идея.

Место, когда я перестал соглашаться, это то, как реализована шаблонизация. Я занимаюсь веб разработкой с 2000 года, и за это время я видел устойчивую тенденцию разграничивать три части веб технологии: стиль, поведение и структура. Я видел (и был частью) этого движения и я думаю вещи, которые поощряют поведение в HTML и HTML в JavaScript — это плохой путь. В конце концов, какая разница между

onclick="foo();"

и
ng-click="foo();"


В окружении вроде XCode, у меня нет проблем с таким стилем привязки в представлении, так как “представление” это не код для меня, а поверхность дизайна. Но с тех пор как мы по другому строим веб, я считаю это плохим направлением развития.

Я бы даже не считал это слабостью, скорее различием подходов. Я думаю слабость Angular это: громоздкое API, факт того что веб-стандарты идут в другом направлении, чем Angular, и то, что абстракции достаточно хрупкие. Достаточно легко оказаться за пределами регулируемого Angular мира, когда понадобится глубокое понимание того как это работает, и где/как вернутся обратно.

Решающим минусом для меня стало, насколько сложно сделать собственную директиву (directive), что я считаю самой ценной возможностью всего фреймворка. За всю мою карьеру, единственная платформа которая приблизилась по уровню мучений при попытке расширить ее, это серверные элементы управления в ASP.net WebForms. Это решаемая проблема, и я думаю если бы мы сейчас были в точке где Angular достиг второй или третьей версии, это был бы мой выбор.

Knockout.js


Knockout применяет вдохновленный Microsoft MVVM подход к фронтенду. У них есть мощный язык для связывания данных (databinding), и привязки html к моделям представлений (view models). У них есть базовый роутер, и это все. Knockout не столько “фреймворк”, сколько хорошая библиотека для связывания данных.

Я думаю идеальное примение Knockout — это когда вы делаете “гибридное” приложение, когда у вас есть взаимодействие между перезагрузками страниц, но сервер по прежнему держит большинство логики. Если это ваш случай, то у вас скромные потребности в клиентской части, и разделение состояния и поведения скорее всего то, что вам нужно.

Слабость Knockout в том, что если вам нужно значительное количество клиентской логики, это станет частью ее решения.

Backbone.js


Backbone — самая популярная фронтенд библиотека этого типа, но также и самая простая. Философия Backbone предоставить минимальный набор вещей необходимый для структурирования фронтенд кода в вебе. Вы можете очень быстро научится использовать Backbone (и прочитать кодовую базу от начала до конца за час), благодаря его простоте.

Использовать Backbone стоит когда у вас скромные потребности (или изначально умеренные, но медленно растущие). Backbone это даже больше философия, чем фреймворк. У Backbone также удивительно активное сообщество, это означает что вы можете “построить собственный фреймворк” выбрав из множества сторонних расширений и библиотек. Backbone очень JavaScript-овый, то есть если вы понимаете язык на котором пишете, вы поймете и фреймворк, так как он делает все в стиле JavaScript.

Слабость Backbone в том, что он действительно не так много делает сам по себе, и вы делаете себе плохую услугу если не знаете что бы подключить в него. Эта “JavaScript-ность” тоже может быть помехой, так как много “веб разработчиков” имеют скудные знания о веб технологии, и если вы из их числа, легко можно затеряться с Backbone.

Backbone.Marionette


Marionette выступает с позиции, что если Backbone предлагает необходимый минимум для структуры любого типа приложения, большие приложения заканчивают с огромным количеством шаблонного кода. Marionette предоставляет структуру необходимую такого рода приложениям, и также дает руководство как организовывать большие объемы кода.

Причина, по которой мы остановили свой выбор на Marionette, — их подход к организации кода, который во многом совпадает с нашим; разделение больших блоков кода на меньшие, которые общаются между собой с помощью хорошо заданных и простых интерфейсов. Разделение управления и вычислений, сделать код представлений как можно более декларативным, а управление кодом — как можно более высокоуровневым. И также следовать устоявшимся паттернам работы с большими и сложными кодовыми базами.

Marionette решает наибольшую проблему Backbone — весь этот шаблонный код в представлениях. Также легко построить свою собственную компонентную архитектуру (что слишком сложно сейчас в Angular), и получить минимальную структуру для всего что нужно (в отличии от Knockout). Потребуется работа чтобы допилить хорошую архитектуру и построить инфраструктуру, но учитывая наши запросы и текущее состояние других библиотек, я думаю это хороший компромисс.

UI это сложно, и нету Серебряной пули


Это оценка конкретной ситуации и точки зрения, и, я верю, имеющая смысл для нашего продукта и нашей команды разработки. Как я уже говорил вначале, все эти варианты прекрасны для своих целей. Если кто-то скажет вам “Я использовал фреймворк X и он плох, но сейчас я использую фреймворк Y и чувствую себя словно я путешествую по солнечным полям на волшебной лошади.”, скорее всего он просто сделал неправильный выбор в первый раз.

Оригинал Автор Мэтт Бриггс (Matt Briggs).
Ads
AdBlock has stolen the banner, but banners are not teeth — they will be back

More

Comments 47

    0
    Спасибо за перевод, интересно.

    А я сейчас отказался от «традиционных» MV* подходов и пробую построить фронтенд-архитектуру по принципу «Modular Javascript» от Закаса.

    Пока что получается нечто, с одной стороны похожее на Яндексовый БЭМ. А с другой не похожее. :)
      +2
      А как модульность конфликтует с MV*-подходами? Или в том скринкасте про какие-то особые другие модули? Компоненты приложений Backbone/Marionette/итд обязательно надо оформлять в виде каких-либо модулей (например, RequireJS/AMD).
        0
        Никак не конфликтует. Просто в случае «modular js» MV* спускается с уровня всего приложения на уровень модулей.

        Основной смысл – отсутствие вообще какой-либо связности между модулями и отсутствие какой-либо бизнес-логики вне модулей.

        Грубо говоря, как я это понимаю: MV* подходы дают вам некий каркас с «пустыми местами» для модулей, а «modular js» полностью строится из модулей, включая сам каркас.
          +2
          Не согласен. У нас вполне успешно используются AMD-модули (require.js) в проектах с Backbone/Marionette, Backbone/Thorax (Backbone/Chaplin, кстати, вообще обязывает использовать модули), Angular, да и вообще в любом проекте в последнее время. На мой взгляд, модули позволяют добиться инкапсуляции, изоляции, независимости между компонентами, а MV*-фреймворки задают структуру самого приложения и определяют (внимание) семантику этих самых модулей. Как любой компонент, так и Backbone-приложение можно написать как олдскульно, так и используя модули. Так что «модули» и «фреймворки» не противоречат, а отлично дополняют друг друга.
            0
            «Использовать модули» != «modular js».
              0
              А в чем разница? Модули — сам концепт. Понятное дело, что использование того или иного формата (AMD/CommonJS) или загрузчика (RequireJS, curl.js, etc) не гарантирует, что приложение концептуально «modular» (однако, best practices по использованию модулей — однозначное использование module-паттернов, иначе какой от них смысл). А что еще?
            0
            отсутствие вообще какой-либо связности
            это надо понимать, что и библиотеки типа jQuery переопределяются у вас в каждом модуле? Интересует, используете ли вы некоторый общий код в базовом модуле, чтобы не повторять его в каждом? И как его переносите, если используете?
              0
              Каждый модуль не знает ничего про jQuery, он знает только про свою песочницу. Каждая песочница знает только про свой модуль и про ядро. Ядро знает только про песочницы и библиотеки (jQuery).

              Что такое «базовый модуль»?
                0
                «базовый модуль» — это то, что в Ваших терминах — ядро. Стало быть, некоторая связность есть, на уровне поставки библиотек. Я себе систему представляю как базовый модуль с либами, который может дополняться другими базовыми модулями с новыми либами или плагинами — это дань оптимизации их загрузки. Модули несут функциональность так, что их может быть достаточно. Но есть и легковесные модули, имеющие только движок событийной связи (postMessage, Custom Event) и чтения либ. В общем, то же самое, только песочницами выступают скоупы модулей.
                  +1
                  Просто посмотрите презентацию Закаса, там всё описано, даже со схемами.
                    0
                    Спасибо, посмотрел. Странное выражение на стр. 100 — «Модули ничего не знают о ядре». А либы? Если модули хотят использовать джиквери?
                      0
                      Насколько я понял, предполагается, что песочница модуля предоставляет ему все необходимые методы (и одновременно контролирует, чтобы модуль не лез к чужим DOM-элементам, например).
        0
        >> промышленного Rails приложения
        Объясните мне кто-то что такое промышленное приложение? Мне вот сразу представляется код управляющий промышленными станками.
          0
          enterprise application, например
            +1
            Имеется ввиду программное обеспечение для решения бизнес задач, применяемое в крупных компания. en.wikipedia.org/wiki/Enterprise_software
            +20
            Спасибо. Сейчас впервые пишу приложение на Angular и получаю огромное удовольствие. Но их парадигма затягивает так сильно и так быстро вытесняет привычный jQuery подход, что становится страшно. Самая большая радость от того, что: приложение летает, путаницы в коде нет, всё структурировано, REST интерфейс в сочетании с Node.js и отсутствие необходимости парсить JSON, встроенная помощь в тестировании контроллеров, директивы, которые можно использовать многократно и постепенно улучшать. Вся информация перед глазами пользователя всегда свежая.

            Чего только стоит: присваиваешь переменной новое значение и везде где оно используется на экране, оно обновится. Я сначала пытался вспомнить, где я это уже видел много лет назад, оказалось Excel уже давно так умеет)

            Удивляюсь, что никто раньше не кричал во весь голос:
            — Эй! Ребята, пишущие при помощи jQuery, изучите современные фреймворки и серверные технологии, начните пользоваться SCSS, где можно спокойно использовать переменные и вложенные стили. Изучите три-четыре команды контроля версий Git, почитайте что такое grunt, научитесь применять стили CSS без кнопки F5 (Live reload), научитесь пользоваться Developer Tools в хроме. Научитесь писать тесты.
            — Это всё сложно! Мы лучше по старинке.
            — Вы так потратите гораздо больше времени и всё равно придёте, но кол-во практического опыта у вас к тому времени станет меньше.

            Обожаю современное состояние инструментов программиста. То ли ещё будет…
              +1
              И ещё испытываю радость от нарушений запретов. Раньше нельзя было использовать глобальные переменные и это считалось плохо. А в Angular ты спокойно объявляешь $scope.peremennaya и можешь её использовать в любых модулях, директивах и контроллерах. Можно даже отправлять сообщения при помощи этой волшебной $scope:
              $scope.$emit("Hello, start bomb please","50000 kilotonn");
              


              А в другом месте можно слушать сообщения:
              $scope.$on('Hello, start bomb please', function(event, data) { jsStartBomb(data); });
              


              PS: Извините, что увлёкся брызжанием слюной. Замолкаю.
                +1
                Насчет глобальных переменных — разумеется, не нужно засорять глобальную область, вместо этого используйте модули и загрузчик :)

                P.S. Это не противоречит использованию scopes (да и modules) в Angular.
                  +1
                  Не совсем понятен пример. Если заменить $scope, на ссылку на объект типа EventManager, то код будет точно таким же и это будет вполне чистый код, без всяких глобальных переменных.
                  Кстати, разных $scope может быть сколько угодно в один момент времени. Всё зависит от того, как они наследуются, что уже противоречит свойствам глобальных переменных.
                    +2
                    Вы немножко неверно понимаете механизм scope. Рассматривайте это скорее, как область видимости, в рамках которой присутствие той или иной переменной оправдано.
                    +1
                    Простите за занудство, но jQuery – это не фреймворк, это библиотека.

                    И каким образом связаны использование того или иного JS-фреймворка\библиотеки с CSS-препроцессорами, сборщиками проектов и инструментами для отладки?
                      0
                      Вы, наверное, профессионал и вам, возможно, трудно понять радости любителя. Восхищение, что когда ты раньше писал лапше код одним способом и при помощи jQuery, а теперь делаешь это там, где твои ребячества не проходят и твоя лапша автоматически группируется в удобные брикеты. Я не к тому, что это всё связано, а к тому, что изучение фреймворков приводит к профессиональному развитию любителей.
                        +2
                        Это всё хорошо, просто если совсем расслабиться, то в случае необходимости будет проблемно написать что-то не на «jQuery» или «Angular», а просто на JS.
                          0
                          Не видел этого топика раньше. Спасибо! )))
                        +2
                        Ну понятно же что имеется ввиду не jQuery, а 'ручное' DOM-манипулирование, кончено после этого MVVM-магия очень доставляет :)
                        +1
                        Попробуйте с помощью Angular и ng-repeat отобразить и заbindить структуру с вложенными коллекциями. В каждом элементе самой глубокой коллекции требуется изменение одного поля, на сервер требуется отправить изменения, структурированные так же, как исходная структура. Для представления требуется также перегруппировать вложенные коллекции по сравнению с исходной структурой. Изменить/упростить представление — не предлагать. Требования реальные: инструментарий локализации интерфейса пользователя. Вложенные коллекции: для каждой локализуемой строки, для каждого языка, между которыми осуществляется перевод, строка, которую нужно отредактировать.

                        Мой опыт на сравнительно небольшом объеме данных показал время компиляции директив более 2-4 секунд зависания браузера, причем это уже на перегруппированной для представления структуре, которую как-то нужно возвращать в исходный вид.

                        В результате свой «велосипед» без binding'а и repeat'ов. Из Angular позаимствовал обработку ввода в текстовое поле. Летает.

                        Вывод: Angular крут для маленьких формочек. Когда дело доходит до коллекций, он меркнет. Будем надеяться, что переход на Object.observe, который идет в отдельной ветке, хоть как-то поможет в runtime (на инициализации при компиляции директив не спасет все равно — DOM штука медленная).

                        P.S. Ember разочаровывает Handlebars'ом и Metamorph'ом.
                          0
                          Может быть проблема в организации самой структуры? Я подобные структуры перед отправкой из «деревянного» вида преобразую в линейный с parent_id и, соответственно, всё отлично ложится на идеологию ресурсов и на сервер отправляется только то, что изменилось.
                            0
                            С отправкой проблем нет, сервер принимает JSON со структурированными изменениями. Проблема с binding'ом на такую структуру с декларативным построением интерфейса пользователя (ng-repeat + другие директивы).
                            0
                            Как решали? Поделитесь. Сейчас стоит задача создать древовидный контрол (4 уровня). Проблема в том, что элементов на послденем уровне овер 80к. Сделал подгрузку 2х последних уровней с сервера, но даже перывые 2 уровня порядка 150-200 элементов рендерятся с задержкой.
                            После этого оставил тоьлко 1 уровень порядка 20 элементов, второй вставляется в дом только при раскрытии. Стало хорошо, но еще нужно навешать фильтров и прочих счетчиков, а это добавит еще кучу проверок на каждый элемент. Все делал через ng-repeat рекурсивно
                              0
                              Никак:
                              В результате свой «велосипед» без binding'а и repeat'ов. Из Angular позаимствовал обработку ввода в текстовое поле. Летает.

                              Это был эксперимент с Angular после прочтения его исходников и вдохновения его крутостью. Такой же эксперимент хотел провести с Ember после аналогичных действий, но уже не осталось времени — нужно было отдавать инструментарий переводчику.
                                0
                                Свой велосипед без биндингов и репитов был написан давно с использованием jQuery и там больше 1000 строк. Пока 70% этого функционала — 80 строк в директиве. Все это ради желания получить читамый и поддерживамый код.
                                  0
                                  Велосипед состоит из следующих деталей. Разметка генерируется на сервере, 125 строк PHP. Интерфейс редактирования — это 642 строки JS (в несжатом виде), которые включают:
                                  — класс-модель, обрабатывающую изменения данных (включая моментальное сохранение в jStorage и отложенную отправку на сервер, не блокирующую редактирование);
                                  — класс-представление, обрабатывающее ввод данных и передающее его в модель, а также отображающее наличие несохраненных изменений — использует jQuery для работы с DOM;
                                  — подробные комментарии с jsdoc'ом к методам.
                                  Для обхода структуры пришлось написать метод, содержащий 6 вложенных for'ов.

                                  На Angular получилось 44 строки HTML-разметки + 170 строк JS, в которых определяется несколько директив для обработки логики. Да, меньше в 3 раза, но там еще нет никакой отправки на сервер, контроля изменений и проч., то есть приложение по сути еще ничего не делает — я бросил на том, что рендеринг завис намертво на несколько секунд.

                                  Писать веб-приложение, используя jQuery — не значит писать бешеные цепочки jQuery(selector).click(callback).find(selector).end().fadeIn(time) и подобные, которые подходят разве что для добавления простой интерактивности в веб-сайты.
                                +1
                                Ну тут нужно понимать, что при необходимости вставки в DOM огромного (тысячи и более) количества элементов — это не решается никаким «фреймворком». Тут нет какой-то серебряной пули, которая позволит все бац — и сделать сверхбыстрым. Всегда есть какой-то лимит количества элементов, после которого все начнет тормозить. Можно только оптимизировать на уровне архитектуры (загрузка кусками, lazy-loading, fetch-on-scroll, и так далее). Если я правильно понял проблему, конечно.
                                  +2
                                  Тормоза образовались из-за того, что Angular не только вставляет в DOM, но и гуляет по тегам и атрибутам в поисках директив. Это очень круто, если директив немного, а вложенность DOM-дерева небольшая (например, для небольших приложений или для приложений, где в один момент времени идет работа с одним ресурсом). Но в случае с `ng-repeat`, внутри которого есть еще куча директив, на время их сбора наступает зависание.
                                    0
                                    А, если речь про директивы — да, тут только workarounds. Впрочем, в любом же фреймворке приходится отступать от основной дорожки и придумывать что-то, чтобы не плодить костыли.
                                  0
                                  Как решали? Поделитесь. Сейчас стоит задача создать древовидный контрол (4 уровня).

                                  Покажу цифры из моего проекта, древовидный список динамических форм (больше среднего размера), если развернуть все объекты и отключить оптимизацию то статистика будет примерно такая: DOM-элементов > 700k, watch'ей > 300k, более 150k директив. Но пользователь все не разворачивает — значит он многое не видит, поэтому нет необходимости обрабатывать большинство элементов прямо сейчас, и мы их отключаем от обработки директивами ng-if, ng-switch и т.п. Плюс ко всему по максимому используется статический биндинг (bind once) где это возможно (bo-if, bo-switch, статические шаблоны {{variable}}). В итоге остается 0,5-1% — что видит пользователь в момент инициализации, этот список сейчас строится примерно за пол секунды на моем буке в crome, в firefox чуть быстрее. Дальнейшая работа пользователя — разворачивание объектов, выполнение команд идет моментально.
                                  0
                                  А чем именно разочаровывает Handlebars?
                                    0
                                    Строковой сборкой и пересборкой HTML (с Metamorph всё сложнее, там еще и добавляется пара тегов script вокруг каждой из меняющихся областей, которые фреймворк находит и меняет текст между ними при обновлении модели).

                                    Возможно, я еще не до конца разобрался (только прочитал исходники, не было времени провести тот же эксперимент, который я провел с Angular). Но в приложении, для которого я рассматриваю переход на один из современных фреймворков с data-binding'ом, есть достаточно нетривиальные вомпоненты, которые выходят за рамки работы с текстовыми данными (например, Flash-объект с ExternalInterface'ом, canvas, video). Эти компоненты невозможно пересоздать из HTML-кода в том же состоянии, в котором фреймворк обнаружил изменение модели. Более того, с Flash-объектом вообще следует поступать осторожно и нельзя удалять и пересоздавать, когда вздумается, поскольку это сторонний плагин, и взаимодействие с ним в некоторых браузерах (апчх-ие) происходит асинхронно.
                                      0
                                      Насчет Handlebars — строковая сборка и пересборка — это проблема именно HB или вообще шаблонизаторов в целом имеется в виду? Так то, вроде, никаких проблем при использовании его с Backbone/Marionette (или Thorax)/Rivets — один раз компилируется и используется дальше.
                                        0
                                        Это проблема строковых шаблонизаторов. Да, оно-то компилируется в функцию, но функция всё равно возвращает строку, которая потом целиком идет в innerHTML. Если в этой строке оказался, например, canvas, то нарисованное на нём с помощью Canvas API изображение при пере-рендеринге шаблона пропадёт.

                                        Или я чего-то не понимаю?
                                          0
                                          Нет, нет, все верно, я просто уточняю. Строковые шаблонизаторы более чем имеют право на жизнь, просто не нужно их использовать для всего и вся. Если есть внедренные объекты canvas, video, swf, итд — тут нужен другой подход, очевидно. В том числе, параллельно использовать Handlebars для одних элементов, но canvas отрисовывать другими средствами. canvas ведь сам по себе держит некоторое состояние, которое может держать, к примеру, какая-нибудь модель, а canvas может быть только «дисплеем». Но тут тоже надо осторожно подходить к задаче — ререндеринг всего canvas-а может быть как оправдан, так и нет. Но этот вопрос далеко за пределами «юрисдикции» Handlebars.
                                +1
                                Решающим минусом для меня стало, насколько сложно сделать собственную директиву (directive)

                                Да вроде всё достаточно просто, не? Простые штуки пишутся не намного сложнее чем с jq (ну разумеется при отталкивании от «Angular way»). Да и при сложных компонентах, при усвоении нескольких правил, всё тоже не так пугающе.

                                И декларативный подход, лично я, не считаю фатальным минусом angular. В действительности, это дает гораздо больше понимания, при беглом осмотре, какую роль играет тот или иной кусок разметки, и даже как себя поведет, и даже кто за это поведение отвечает. Да, on-click, ну дык и что? =) По сути — имеющее право на жизнь удобство =)
                                  0
                                  См. мой комментарий выше. Хотелось именно декларативности, с преобразованием из одной структуры в другую и автосохранением. Пришлось делать по-старинке.
                                  +1
                                  Марионетка очень понравилась, правда порог вхождения высоковат, сам пару дней просидел тыкав до просветления. Для старта приложения очень рекомендую посмотреть на заготовку https://github.com/juanghurtado/puppeteer
                                    +4
                                    Не нашёл там JS, к сожалению. Все исходники на CoffeeScript :(
                                      0
                                      С удовольствием использую CoffeeScript для проектов на php и ruby on rails.
                                    0
                                    Следующий шаг — full-stack фреймворки

                                    Only users with full accounts can post comments. Log in, please.