Pull to refresh

Comments 58

Я извиняюсь, но объясните, пожалуйста, за что минусы (включая карму)? На хабре уже вешают за благодарность? о_0
Полагаю, что это из-за того, что ваш комментарий не несёт полезной читателям нагрузки (благодарность можно автору и в личку написать). Но это только моё предположение (минусы не мои).
Ну вот, теперь и мне минусов насыпали :) А я меж тем всего-навсего пытался объяснить возможную мотивацию тех, кто, вероятно, минусы ставил (сам я ничего страшного не вижу в том, что порой благодарят автора в комментарии).
Занимательное чтиво, а будут ли сравнения с другими js фреймворками, тесты?
UFO just landed and posted this here
Там по большей части сравнение с jQuery, судя по заключению:
Не использовать DOM для хранения данных
т.к. упомянутые там Ember и Backbone вроде как не используют DOM для хранения данных.
Хочется тесты в сравнении с другими фреймворками, особенно с Angular.js, которые можно «пощупать», наподобие jsfiddle.net/lega911/ZUne7/
Там по большей части сравнение с jQuery

Не совсем. Если вы о докладе про данные, то там объясняется почему чаще всего медленно работает на больших количествах данных. Хранение данных в DOM наиболее частая ошибка, которая приводит к печальным результатам.

т.к. упомянутые там Ember и Backbone вроде как не используют DOM для хранения данных.

Они сами нет, но их пользователи – да. Когда стравниваются backbone и ember речь идет чисто про данные, и DOM уже не затрагивается, сравниваются разные реализации.

Хочется тесты в сравнении с другими фреймворками, особенно с Angular.js, которые можно «пощупать», наподобие

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

Ваш тест плохо организован. Не совсем понятно что вы тестируете. На результаты влияют посторонние факторы и особенность организации теста.
Так же не стоит использовать new Date, так как он не дает точность (например в Chrome дискретность 16ms). Нужно использовать performance.now() если доступен, и если нет – тогда new Date. Хотя там такие цифры что это не так страшно :)
Я добавил basis в тест: jsfiddle.net/GdE3r/1/
Цифры говорят сами за себя ;) И это при том, что другие создают только разметку, а basis – полноценные интерфейсные узлы, а у них богатый функционал.
Это не мой тест, он от сюда: Toster — Angular vs Knockout на больших списках.
Ваш вариант у меня не работает (Chrome 33), мне кажется basis пытается брать зависимости не от туда:
GET http://fiddle.jshell.net/GdE3r/1/show/light/basis/ui.js 404 (Not Found)
Ну вот, вам и пример. Используя angular вы смогли сделать все решения гораздо медленнее, чем они есть на самом деле.

Вот цифры по вашей ссылке


А вот я немного переделал сам тест (методы clear просто делают свою работу, без вызова callback и меньше таймеров), и получилось так:


Выходит в вашем варианте не правильно измерялось и тестировалось, так как это добавило значительные накладные расходы (шутка ли jQuery на заполнении был в два раза медленнее, Knockout — в 3, basis.js — в 6). Малое влияние изменений на Angular Light (inline) видимо из-за того, что использовались его таймеры.
Выходит в вашем варианте не правильно измерялось и тестировалось
Нет, просто там дополнительно учитывается время рендеринга. Посмотрите в вашем варианте на Knockout.js 595ms и Angular.js 1075ms, у KO время лучше хотя визуально видно что он отрисовывается в 2 раза медленнее — т.е. цифры врут.

Используя angular вы смогли сделать все решения гораздо медленнее, чем они есть на самом деле.
Так оно, но это плата за «удобства», а в реальных приложениях «узкие» места можно переписать на vanilla js, например для теста выше можно было сделать директиву ng-fast-list которая не уступала бы по скорости.
Нет, просто там дополнительно учитывается время рендеринга. Посмотрите в вашем варианте на Knockout.js 595ms и Angular.js 1075ms, у KO время лучше хотя визуально видно что он отрисовывается в 2 раза медленнее — т.е. цифры врут.

У того и другого свои заморочки с отложенными вычислениями.
Учитывать время рендеринга (именно отрисовки) нет смысла. Во-первых, это уже не часть измеряемого кода. Во-вторых вы не можете гарантированно сказать, когда он отработает.
То есть если мы изменяем скорость какого-то решения в целом, то имеет смысл включать все расходы (но через js всего не измерить). А если мы делаем тест, сравнивающий разные решения, то нет смысла включать оверхед, общий для всех.
В целом, я с вами согласен, что выпал рендеринг. Он занимает примерно одинаковое время. Если посмотреть на цифры, то для jQuery, Angular и basis.js цифры поменялись примерно одинаково, то есть на ~250ms на заполнении и ~150ms на обновлении. То что так сильно упало время для Knockout, скорей говорит о том, что часть работы он делает отложено и это не попадает в результат. Для Angular Light время заполнения уменьшилось больше чем на 250ms, возможно тоже что-то не учлось (или погрешность), зато обновление похоже на правду. Почему время Angular Light (inline) осталось неизменным, для меня загадка. Я думаю, что в обоих случаях выпадает часть работы. Так как в вашем варианте он близок к basis.js, но визуально работает в несколько раз медленнее.

Так оно, но это плата за «удобства», а в реальных приложениях «узкие» места можно переписать на vanilla js, например для теста выше можно было сделать директиву ng-fast-list которая не уступала бы по скорости.

Если честно, не увидел особых удобств. Код на angular запутан и его не назовешь «изящным» (но, возможно, это дело вкуса, конечно). И это на простой задаче, а если мы начнем добавляться функционал, то вы быстро обрастете кодом, и решение станет еще более запутанным.
Можно сделать дерективу? Сделайте, было бы интересно увидеть результаты. Но тогда нужно учитывать, что, например, для того же basis.js так же можно не создавать UI ноды, а использовать чисто шаблонизатор. Будет в 2-3 раза быстрее, но код будет «не очень» и не будет многих «удобств» (basis.ui как раз прячет за своим интерфейсом всю «неприятную» работу). Добавил реализацию для сравнения (файл bs_template.js).
Я думаю, что в обоих случаях выпадает часть работы. Так как в вашем варианте он близок к basis.js, но визуально работает в несколько раз медленнее.
В Angular Light ничего не «выпадает», все действия отрабатывают последовательно (в одной «итерации»).

Код на angular запутан и его не назовешь «изящным» (но, возможно, это дело вкуса, конечно). И это на простой задаче, а если мы начнем добавляться функционал, то вы быстро обрастете кодом, и решение станет еще более запутанным.
Разрабатывал большие веб-приложения на Angular, не возникло проблем с запутаностью кода.

Можно сделать дерективу? Сделайте, было бы интересно увидеть результаты.
Вот, конечно это крайний вариант, без шаблонизатора, но показывает до куда можно опуститься, по сути директива просто дает точку позиционирования = элемент + данные, далее вы делаете что угодно.
Сейчас у меня такой результат:
JS: 19 — 10
al-fast-list: 21 — 10
Basis.js template: 55 — 18
В Angular Light ничего не «выпадает», все действия отрабатывают последовательно (в одной «итерации»).

Тогда как вы объясните одинаковые результаты и что визуально оно отрабатывает медленнее?

Разрабатывал большие веб-приложения на Angular, не возникло проблем с запутаностью кода.

Возможно, у нас разные представления о больших приложениях.

Вот, конечно это крайний вариант, без шаблонизатора, но показывает до куда можно опуститься, по сути директива просто дает точку позиционирования = элемент + данные, далее вы делаете что угодно.

Очень здорово, что добавили вариант с plain js. Да, так можно увидеть базовую линию, то есть ниже которой не опуститься. Заполнение правда можно сделать еще быстрее если сгенерить строку со всем html, и запихнуть через innerHTML. Правда в этом случае у нас не будет ссылок на элементы и обновление будет в несколько раз медленнее (если использовать ту же технику).
Любой шаблонизатор создает overhead, плата за универсальность, все дела. Но, по-моему, не плохой результат. Что скажете?
А реализация директивы это больше хак, чем реальное применение. То же можно проделать практически для любого решения. Так что можно сказать, что это «неспортивное поведение» ;)
Основная проблема с plain js (и соотвественно директивой), что если нам нужно поменять разметку, добавить больше значений, обработчики событий и т.д., динамически менять все это, и эти изменения делаются в множестве мест… я думаю, вы сами прекрасно знаете, что будет :)

P.S. Сначала подумал, странно что цифры выросли. И лишь потом заметил, что речь уже про 10k элементов, а не 4k :) Knockout все так же неправильно считается, у меня висит секунд 15 наверное, а показывает 1.5 — странно все это.
Тогда как вы объясните одинаковые результаты и что визуально оно отрабатывает медленнее?
У меня оно соотносится с цифрами — визуально чуть быстрее чем Angular.js

Возможно, у нас разные представления о больших приложениях.
Возможно, но Angular так же и официально, «покрывает» нишу больших приложений.

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

Но, по-моему, не плохой результат. Что скажете?
Да, результат очень хороший.

Основная проблема с plain js (и соотвественно директивой), что если нам нужно поменять разметку
Какая разница, я просто показал что это достаточно гибко, если нужен уровень чуть выше чем js, то можно вставить тот же Basis.template или любой другой шаблонизатор.

Так что можно сказать, что это «неспортивное поведение» ;)
Я просто показал как можно победить узкие места, да и вообще по большому счету большинство синтетических тестов показывают «сферического коня».
У меня оно соотносится с цифрами — визуально чуть быстрее чем Angular.js

Я говорил про соотношение с basis.js. По ощущениям, последний визуально отрабатывает гораздо быстрее, хотя время выводится близкое…

Возможно, но Angular так же и официально, «покрывает» нишу больших приложений.

Ок. Тогда, хотелось бы от вас услышать характеристики большого приложения.

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

В целом, да. Но это так определяется порог, когда вам нужно прибегать к «хакам».
У большинства «мейнстримовых» решений проблема именно в этом. Когда начинаем работать с большими количеством данными, начинаются проблемы, нужно думать про всякие «хаки». Мне кажется, что фреймворк должен подводить к этому на каких то безумных количествах, например, сотнях тысяч или миллионах моделей. Но не раньше (на тысячах).
В общем, в тесте была проблема, так что неправильно измерялось время для многих решений, из-за того, что они делают вычисления отложено (angular, knockout etc). Фактически не учитывался вызов callback.
Я поправил, теперь больше похоже на правду: plnkr.co/edit/RzZP7146NgWHlVchXZF7?p=preview
Чтобы не считать расходы на рендеринг я спрятал блок, куда рендерятся списки. Добавил галочку, чтобы можно было учитывать это время. Можно заметить, что даже спрятать/показать список из 10k элементов получается не быстро. Это время у всех будет практически одинаковым.
Смущает, что используется setTimeout(callback, 0) — это может накидывать дополнительное время.
Так же tenshi добавил свое решение и немного изменил решения на jQuery и Knockout, они стали побыстрее.
В итоге у меня получились такие цифры:



Конечно, нужно измерять каждое решение в отдельности. Некоторые, особо прожорливые до памяти, съедают ее столько, что это сильно сказывается на времени выполнения других.
Этого точно не будет в руководстве, но возможно будет отдельная статья.
Как правильно заметил vk2, некоторые сравнения есть практически в любой презентации – www.slideshare.net/basisjs/
К теме сравнения, вот расширенный тест Jeremy Ashkenas с анимированными кружочками:

Меня интересует несколько моментов:
1) Я так понимаю, что default оформление ui было взято у sencha? Как они к этому относятся?
2) Самописная билд система? Почему не используете уже существующие?
3) Какие решения вы используете для наследования и что вы думаете о примесях
4) Скоро современные браузеры начнут поддерживать ES6, не сигнал ли это к приведению кода к ES6 нотации, особенно для новых фреймворков? Я имею ввиду, что можно уже сейчас реализовывать большую часть спецификации, а поддержку старых браузеров обеспечивать полифилами. Это дало бы вам некоторую отличительную особенность, по сравнению с основными frontend фреймворками.

Вообще, почти любой труд заслуживает благодарности, и я уверен, что ваш фреймворк найдет свою нишу, но пока я не понимаю, чем он принципиально отличается от остальных. Присоединяюсь к xeLL, хотелось бы посмотреть на сравнение бенчмарков с др. фреймворками.
Справедливо добавить, что после просмотра презентации, ссылку на которую кинул vk2, вопрос про сравнение с фреймворками отпадает. Но все же, я думаю было бы лучше, если б вы добавили эту информацию в статью.
Чуток истории. Если я хорошо помню, то Basis Рома начал делать еще в 2006 году, если не раньше. А вот оформление UI он делал при мне году так в 2008 — и за базу он брал оформление OS Windows Vista. Сидел вырезал бекграунды со скриншотов и т.п. :)
1. sencha никак к этому не относится, так оформление взято не у них. Возможно оформление вам показалось знакомым из-за использование сине-голубых оттенков. Но это больше заимствование от windows разных версий + собственные додумки. В целом, дефолтные стили используются редко, там где не важен дизайн. А в большинстве случаев переопределяются шаблоны или пишутся собственные компоненты.
2. Причина номер один: когда начинали делать сборщик, не было ни grunt, ни gulp, ни broccoli, ни чего то подобного. Во-вторых, мне, например, не известны системы сборки которые умеют строить граф файлов и производить оптимизации на основе их типов и взаимосвязей. В нашем случае, сборка нечто большее, чем просто «возьми файлы из этой папки, объедини и прогони через упаковщик». К тому же используется CommonJS, а он так просто не собирается. Думаю, об этом еще будет отдельная статья.
3. Про классы и наследование можно прочитать тут. Примеси практически не используются и, в целом, не очень хорошая идея.
4. В принципе ничего не мешает использовать ES6 уже сегодня с любыми фреймворками и библиотеками, надо лишь обеспечить трансляцию ES6 -> ES5. Это не задача фреймворка. Но есть мысли, например, по поводу использования синтаксиса для работы с модулями (import).

Спасибо. Если посмотреть на все фреймворки, то они ничем друг от друга не отличаются, все они фреймворки и написаны на javascript :)
Конечно, я слышал о нем и даже лично знаком с текущим мейнтейнером :)
Борщик гораздо проще и не делает анализа кода или организации проекта.
Разработчикам всегда интересно повышать эффективность кода, не изменяя своих привычек :-)
Отсюда и вопросы про борщик\грант и прочее.

Скорее народ интересует вот что: планируете ли вы интеграцию своих решений во что-нибудь мейнстримовое? Чтобы полностью не менять привычную среду разработки. Та же сборка проекта борщиком с флагом basis, например, который будет проводить необходимый анализ кода организации проекта.
Насчет борщика таких мыслей не было. А насчет grunt/gulp были… но есть нюансы ;)
Мы стараемся не делать решений на перспективу, у всего должен быть свой пользователь, чтобы сказать как правильно и насколько решение хорошее. Если будет необходимость в интеграции, то неприменно что нибудь придумаем ;) Тем более, что basisjs-tools можно использовать как модуль в своих скриптах (на это был расчет при проектировании).
К сожалению, ситуация вокруг сборщика немного сложнее: у вас, насколько я понимаю, нет возможности инкриментальных сборок, нет кеширования, watcher'ов. А это значит, что либо мне придется работать с двумя сборщиками, например, Gulp и ваш, либо писать свои велосипеды для оборачивания shell команд под CoffeeScript или SASS, что явно не упрощает процесс разработки. Это уже не говоря, про, скажем, разделение окружений на dev и production для сборок. А по поводу commonJS, уже есть решения для разнообразных билд систем, в чём такая сложность его сборки? Что касается «киллер-фичи» с графами файлов — вам ничего не мешает вынести ее как плагин к одной из готовых систем, это намного проще, чем писать очередной сборщик. По поводу ES6 — это не задача фреймворка, но когда стандарт будет увтержден, лично я отдам предпочтение фреймворкам, которые будут иметь нативную поддержку таких вещей, как модули, например, чем буду использовать amd/commonJS. Разумеется, это всё лишь моё мнение и я не претендую, что оно единственное правильное.

P.S. Если посмотреть на все фреймворки, то они отличаются друг от друга подходом к созданию приложений. Например, я думаю, многие не согласятся с вашим мнением, что Backbone не отличается от Angular.
Инкрементальной сборки нет, вы правы. По той причине, что сборка нужна только для публикации приложения, но не для разработки. Кеширование есть на уровне dev-сервера, он запоминает (текстовые) файлы, которые запрашивает клиент и при перезагрузке отдает множество файлов как один, тем самым уменьшая количество запросов и время загрузки. Так даже приложение на 1500 файлов обновляется быстро (что-то вроде 1сек). Хотя, как написано в статье, обновление нужно только если вы обновляете html или javascript.
Что касается компилируемого контента, таких как coffeescript, sass и т.п., то тут все зависит от самого решения. Например, у coffeescript есть компилятор написанный на js, это значит что мы можем транслировать его в js хоть на сервере, хоть на клиенте. И если вы пройдете по этой ссылке, то увидите как это сделать, как раз на примере coffeescript. Что касается sass, то тут немного сложнее, так как компилятор на ruby. Можно использовать какой нибудь вотчер, который будет транслировать файлы в css при их изменении, а дальше все будет работать как раньше. Другой вариант, чтобы это делал dev-сервер и сборщик. Этого пока нет, так как не существовало спроса на эту функциональность. Но это совсем не проблема имплементировать, там все относительно не сложно.
Насчет графа файлов, вы недооцениваете задачу и пока не видите преимуществ. Основной смысл, что мы не просто обрабатываем какие то файлы, но строим их взаимосвязи и понимаем как они друг друга используют. Вот, например, вся верстка у нас в шаблонах, а стили в css. Мы можем найти соответствия и нестыковки. Например, что такой то класс никогда не используется в разметке, а вот для этого класса в шаблоне нет никаких стилей. Поэтому мы можем на этапе разработки рассказать о ряде проблем, а на этапе сборке применить агрессивную оптимизацию, которая заменит все классы и id на одно-двух буквенные. Это как, например.
То есть суть в том, что обрабатывается не просто какой то определенный файл, или тип файлов. А обрабатываются все файлы сразу, с учетом их связей, перестраиваются структуры. Например, те же шаблоны попадают в сборку в виде AST, которое уже не требует парсинга. И т.д.

P.S. Это была шутка ;) И, кстати, ни Backbone, ни Angular не являются фрейморками, если что…
сборка нужна только для публикации приложения, но не для разработки

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

Например, у coffeescript есть компилятор написанный на js, это значит что мы можем транслировать его в js хоть на сервере, хоть на клиенте.

Только что вам даст трансляция coffee->js без возможности сохранить результат? Или вы будете eval'ить код, который будет выходить из такого транслятора? И будете делать это для всех coffee файлов? Я могу сказать, что вы здесь ничего не выигрываете.

Можно использовать какой нибудь вотчер, который будет транслировать файлы в css при их изменении, а дальше все будет работать как раньше.

Действительно, можно, однако инкрементальные сборки придумали как раз, чтобы уйти от того, что у вас в одной вкладки консоли открыт sass watch, в другой coffee watch, а в третей бог весть что. И более того, это по-прежнему не покрывает кейсов тестирования после изменения coffee файлов.

не существовало спроса на эту функциональность

Вы считаете, что таск-раннеры а-ля Grunt, или системы сборки типо Gulp, Broccoli, Brunch не пользуются спросом?

Основной смысл, что мы не просто обрабатываем какие то файлы, но строим их взаимосвязи и понимаем как они друг друга используют

То есть суть в том, что обрабатывается не просто какой то определенный файл, или тип файлов. А обрабатываются все файлы сразу, с учетом их связей, перестраиваются структуры

Не могу представить себе иного сценария, как файл index.html как корень графа, из которого идут две ветви: css и js, в которых в css отражаются зависимости директивы @import, а в js — amd/commonJS модулей. Как это помогает разработке?

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

Chrome Dev Tools -> вкладка audit -> start

ни Backbone, ни Angular не являются фрейморками, если что…

Не могли бы вы в таком случае пояснить мне, чем они являются, если не MV* фреймворками?
Лично я основвываюсь классического определения «фреймворк», данного википедией, и в моём понимании, angular и backbone под него подходят
Что насчет тестирования? Я придерживаюсь разработки через тестирование, и т.к. я тестирую не отдельные функции, а пользовательские сценарии, я бы хотел иметь собранный проект, т.к. чаще всего пользовательские действия затрагивают сразу несколько модулей, как быть тогда?


Отсутсвие сборки никак не мешает тестированию. Или я чего-то не понимаю?

Только что вам даст трансляция coffee->js без возможности сохранить результат? Или вы будете eval'ить код, который будет выходить из такого транслятора? И будете делать это для всех coffee файлов? Я могу сказать, что вы здесь ничего не выигрываете.


А зачем его сохранять? Да, код будет eval'ится (через new Function). Так же eval'ится и код всех модулей, на этом построена работа commonjs. Node.js делает точно так же. И, поверьте, в этом нет проблемы.
Когда вы делаете сборку, то в процессе код оборачивается в функции и в собранном варианте уже не будет eval'ится.
Здесь дело не в мифическом выигрыше, а в удобстве. Например, вам не нужно хранить временные файлы (результат компиляции coffeescript), если код не скомпилится вы увидите это в консоли браузера, в панели sources вы видите все файлы ровно так как они располагаются в вашей файловой системе etc.

Действительно, можно, однако инкрементальные сборки придумали как раз, чтобы уйти от того, что у вас в одной вкладки консоли открыт sass watch, в другой coffee watch, а в третей бог весть что. И более того, это по-прежнему не покрывает кейсов тестирования после изменения coffee файлов.


Если нет какой то функции, и она нужна — ее можно добавить. В вашем примере вотчер нужен только для sass.
Предполагаю, что мы подумаем насчет системы плагинов и тогда можно будет использовать один вотчер для любых файлов и работ, в том числе и для sass. В конечном итоге, проект open source и вы сами можете поучавствовать в имплементации необходимого функционала.

Вы считаете, что таск-раннеры а-ля Grunt, или системы сборки типо Gulp, Broccoli, Brunch не пользуются спросом?


Вы меня не правильно поняли, речь шла о поддержке sass в basisjs-tools, а не о таск-раннерах.

Не могу представить себе иного сценария, как файл index.html как корень графа, из которого идут две ветви: css и js, в которых в css отражаются зависимости директивы import, а в js — amd/commonJS модулей. Как это помогает разработке?


Html подключает javascript, css, изображения и другие файлы. Javascript подключает другие javascript модули и другой контент, такой как шаблоны, словари, json etc, для некоторых вещей свои синтаксические конструкции. Шаблоны — css, изображения, словари, другие шаблоны. И далее…

Chrome Dev Tools -> вкладка audit -> start


У вас всегда вся возможная разметка на странице? Речь не про статичные сайты, а про приложения, где динамически генерируются, вставляются, удаляются представления в зависимости от ситуации, а еще добавляются и удаляются классы, меняется разметка. Вариантов состояния разметки настолько много, что вы просто не сможете сделать так, чтобы audit правильно показал что используется, а что нет. Если речь, конечно, не про «Hello world» ;)
Отсутсвие сборки никак не мешает тестированию. Или я чего-то не понимаю?

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

А зачем его сохранять? Да, код будет eval'ится (через new Function). Так же eval'ится и код всех модулей, на этом построена работа commonjs. Node.js делает точно так же. И, поверьте, в этом нет проблемы.

А что насчет минификации выходных файлов? Суть в том, чтобы после трансляции coffee->js склеить и минифицировать все JS файлы. Как вы это будете делать, если собираетесь компилировать Coffee на клиенте? Это проигрыш в скорости, как с точки зрения eval'a, так и с точки зрения трафика.

Html подключает javascript, css, изображения и другие файлы. Javascript подключает другие javascript модули и другой контент, такой как шаблоны, словари, json etc, для некоторых вещей свои синтаксические конструкции. Шаблоны — css, изображения, словари, другие шаблоны. И далее…

Ну, во-первых это очень похоже на web-компоненты(см. polymer, mozilla x-tags), особенно идея с подключением стилей для конкретных объектов. По-факту, ваша система позволяет производить инкапсуляцию css, js и html в рамках компонента, верно? В таком случае это 1 в 1 повторяет идеологию web-компонентов.

У вас всегда вся возможная разметка на странице?

Нет, но у меня всегда подключается gzip-пакет, в котором лежат все JS и CSS. А т.к. мои «фреймворки» позволяют мне выбрать шаблонизатор, с которым я буду работать, то компилируется этот код в JS, и позднее склеивается и минифицируется вместе с остальными JS файлами, тем самым получая максимально маленький размер трафика, который мне надо отдать пользователю. Это уже не говоря о том, что я могу провести вашу проверку на использование стилей в несколько раз быстрее, пробежав всего по 2 файлам: 1 css(результирующий) и 1 js(шаблоны), в то время как при вашем подходе мне придется открывать по 1 все стили и все шаблоны.
Unit-тестированию не мешает, а функциональному тестированию мешает. Вы не можете провести функциональное тестирование до момента создания консистентного состояния системы, которое достигается успешной сборкой проекта.

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

А что насчет минификации выходных файлов? Суть в том, чтобы после трансляции coffee->js склеить и минифицировать все JS файлы. Как вы это будете делать, если собираетесь компилировать Coffee на клиенте? Это проигрыш в скорости, как с точки зрения eval'a, так и с точки зрения трафика.

По той ссылке, что я вам привел есть и про сборку. При сборке coffee будет транслироваться в js, этот код будет обернут, проанализирован, сконкатенирован и минимизирован на ряду с остальным javascript. Трансляция coffee->js на клиенте происходит только в dev режиме.

Ну, во-первых это очень похоже на web-компоненты(см. polymer, mozilla x-tags), особенно идея с подключением стилей для конкретных объектов. По-факту, ваша система позволяет производить инкапсуляцию css, js и html в рамках компонента, верно? В таком случае это 1 в 1 повторяет идеологию web-компонентов.

Да, верно подмечено, это похоже на web-components. Но там есть ряд отличий и шаблоны basis.js дают гораздо больше, чем просто инкапсуляция.

Нет, но у меня всегда подключается gzip-пакет, в котором лежат все JS и CSS. А т.к. мои «фреймворки» позволяют мне выбрать шаблонизатор, с которым я буду работать, то компилируется этот код в JS, и позднее склеивается и минифицируется вместе с остальными JS файлами, тем самым получая максимально маленький размер трафика, который мне надо отдать пользователю. Это уже не говоря о том, что я могу провести вашу проверку на использование стилей в несколько раз быстрее, пробежав всего по 2 файлам: 1 css(результирующий) и 1 js(шаблоны), в то время как при вашем подходе мне придется открывать по 1 все стили и все шаблоны.

Как я уже писал, сборщик basisjs-tools тоже оптимизирует структуру шаблонов при сборке.
Пробежаться у вас вряд ли получится, потому что шаблонизаторы, те что вы имеете ввиду, прозводят функции, которые конкатенируют строки. Вы не можете предсказать результат такой конкатенации, так как там подставляются значения (переменные). Поэтому это одна из главных проблем — узнать на каком элементе, какие классы бывают. А еще, в таком подходе, те же классы часто меняются из представления. Например, $(this.el).addClass('foo-' + bar + '-' + baz) — вы можете сказать какой класс тут будет в результате? Вам так же не поможет поиск, если вы видите класс в селекторе, вы не сможете его найти в шаблоне, если он динамический, и так просто ответить на вопрос используется ли он.
В «нашем» подходе не нужно открывать файлы по одному. Вы просто описываете шаблоны и стили. В basisjs-tools есть команда extract, которая позволяет извлекать факты о вашем приложении. По сути она выполняется перед сборкой, так как сборщик использует эту иформацию, чтобы уже произвести результат. Так вот, вызвав такую команду можно получить список проблем, вам напишут в каком файле и какая проблема. Так как вы разрабатываете постепенно, то так же постепенно и исправляете проблемы и миллиона варнингов вы не увидите. Можно так же использовать плагин для Google Chrome (про который говорилось в статье), тогда не нужно выполнять эту команду, а можно посмотреть все варнинги в Developer Tools -> basis.js -> Warnings. На скриншоте, как раз видно сейчас в проекте 2 варнинга, они как раз про то, что использованы id для которых нет стилей.
Да, верно подмечено, это похоже на web-components. Но там есть ряд отличий и шаблоны basis.js дают гораздо больше, чем просто инкапсуляция.

Хотелось бы услышать об этом во второй части статьи

Например, $(this.el).addClass('foo-' + bar + '-' + baz) — вы можете сказать какой класс тут будет в результате?

Да, вы правы, такое крайне тяжело разобрать. Но я не до конца понимаю, в таком случае, как вы это делаете?

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

Спасибо за статью, жду продолжения с описанием привязки контролов к состоянию модели.
Интересно было бы прочесть об организации контроллеров и роутингов.
А так, напомнило ExtJS способами описания конфигов представлений.
Как таковых контроллеров нет. Но если рассуждать согласно, например, вот этой штуке, то контроллер это basis.ui.Node, а представление это шаблон. Хотя многие говорят что у нас тут MVVM. Но, честно говоря, мы не особо заморачиваемся насчет классификации ;)
Про роутер будет следующих частях, скорей всего в третьей.
Очень похож на суррогат ExtJS. Похоже, что ребята решили сделать что-то свое в этом направлении, только недопили до конца. Идея интересная, посмотрим как будет развиваться.
Простите, но в каком месте это суррогат ExtJS?
Боюсь, что вы рано делаете выводы, это всего лишь первая часть руководства и в нем рассказана лишь малая часть из того, что есть во фреймворке ;)
Когда basis только начали создавать ExtJs даже еще не родился.
По-моему, все просто имеют ввиду, что фреймворк «опоздал» на несколько лет. В далеком 2006 это был бы огромный прорыв вперед, но в 2014 это просто еще один фреймворк на JS. Если вы со мной не согласны — объясните, в чём он «уникален», т.к. из статьи этого не понятно.
Уникальность фреймворка, он очень высоко производительный. Он граматно работает с DOM, возможно лучшая реализация, какую-либо я втречал. C ExtJS имеет общее только тем, что в своей основе использует компонентный подход(что-то подобное на дерективы из «ангуляра» или web components). У ExtJS, есть большой недостаток он плохо кастомизируется. Хотя существует много и других недостатков, но это бы назвал основным.
Basisjs Уникален своими инструментами, написанными на привычном для фронтеенд разработчика стеке. В инструментах есть почти все, что вам может понадобиться. Есть киллер фича лайв редактирование.
Фреймворк, очень хорошо подходит для больших проектов. Он заставляет писать вас быстрый код. Модульная система позволит вам переиспользовать ваш код без боли, даже в другом проекте.
Есть и недостатки, но я не буду о них упоминать.)
Я советую, Вам познакомиться ближе с фреймворком, попробуйте его. Из описания действительно не видно его крутости.
Я думаю, Роман раскроет в следующих статьях все прелести basisjs.
Вообще молодцы ребята, что продолжают развивать проект, а не зарыли его внутри компании, и пытаются поделиться большим опытом разработки действительно сложных фронтенд систем.
Уникальность фреймворка, он очень высоко производительный

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

Есть киллер фича лайв редактирование.

livereload.com/ — а такое решение не устраивает? Или я что-то не так понял?

Фреймворк, очень хорошо подходит для больших проектов

Как и любой другой фреймворк, собственно.

Уникален своими инструментами, написанными на привычном для фронтеенд разработчика стеке

Можно поинтересоваться, какие инструменты в этом фреймворке уникальны?

Модульная система позволит вам переиспользовать ваш код без боли, даже в другом проекте.

Это не достоинство фреймворка, это достоинство модульной системы.

Есть и недостатки, но я не буду о них упоминать.)

Почему? У читателей, на мой взгляд, должно складываться комплексное впечатление о фреймворке, который они, возможно, захотят использовать в сл. проекте.

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

А за это и правда большое спасибо. В любом случае — это вклад в развитие экосистемы JS, и весьма немалый.
Хотелось бы в дополнение к слайдам увидеть бэнчмарки, отражающие заявленные цифры

basisjs.com/basisjs/test/speed/tree.html Это конечно синтетические примеры, но хоть что-то.

livereload.com/ — а такое решение не устраивает? Или я что-то не так понял?

Нет чуть другое. Просто попбробуйте. Это нужно просто увидеть. У basisjs, очень хорошее разделении на данных и представления.
Как и любой другой фреймворк, собственно.

По опыту скажу, что не все. Иногда с ростом приложения, вам придется «бороться» с фрэймворком, а не только со сложностью вашего приложения.
Можно поинтересоваться, какие инструменты в этом фреймворке уникальны?

Уникальны не инструменты, а то что у вас из коробки есть экоситема для разработки на basisjs. Нет необходимости искать, нужный вам инструмент.
Это не достоинство фреймворка, это достоинство модульной системы.

Достоинство, как реализованна это модульность. И какие концепты заложены в архитектуру.

О недостатках. Мало реальных примеров и гайдов. Но как видим ситуация улучшается.
Порог вхождения, я бы не назвал низким. Подходы в разработке, отличаются от имеющихся сейчас популярных фреймворков(это мое мнение). Маленькое комьюнити или вообще его отсутсвие. Я бы не рекомендовал, начинать проект на basisjs, если вы не очень опытный разработчик.
Я кстати, никаким боком не отношусь к созданию или разработке фрэймворка. Говорю со стороны пользователя.
Спасибо за ссылку на бэнчмарки, поглядел — действительно все очень быстро. По поводу лайв редактирования по-прежнему не понимаю: может, вы имеете ввиду data-binding? Я просто уже теряюсь в догадках :) По поводу «бороться» с фреймворком — это скорее просто говорит об отсутствии правильно спроектированной архитектуры.

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

Таких тестов, чтоб «бери и пробуй» пока мало. Вот один из них, что я делал для последнего доклада: тест моделей lahmatiy.github.io/lib-compare/ (репозитарий), сравниваются два разных модуля basis, Backbone и Ember.

livereload.com/ — а такое решение не устраивает? Или я что-то не так понял?


Livereload и подобные, перегружают страницу, когда меняется какой то файл. С basis.js вам нужно это делать только для javascript файлов. Если вы меняете шаблоны, стили или словари локализации этого делать не надо. Базис перестраивает часть страницы, применяя изменения. То есть в этом случае нет перезагрузки страницы. Это не критично для сайтов, но очень критично для приложений, так как нам нужно сохранять состояние. Я планирую записать скринкаст, думаю из него все станет ясно. А пока можете либо проследовать руководству, и попробовать у себя. Либо поиграться в интерактивном туре, например, на этом слайде: basisjs.com/basisjs/tour/#ui_loose_coupling. Там сверху можно переключать закладки (файлы), код можно менять. Попробуйте выбрать пункт списка внизу, а потом менять файлы *.tmpl или *.css.

Фреймворк, очень хорошо подходит для больших проектов
Как и любой другой фреймворк, собственно.


Все очень зависит от того про какие размеры мы говорим, для каждого это своя цифра. Для меня большой проект это сотня другая модулей, еще больше представлений, десятки типов данных (моделей), тысяча другая файлов. В такой ситуации важно насколько читаемый код в итоге получается. Насколько просто реструктурировать проект, находить проблемы и понимать откуда «ноги растут» (например, вот кнопка — а в каком модуле она описана, где ее шаблон?).

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


Очень хорошо сказано :) Правда фреймворку уже 7-8 лет… но он только начинает выходить, так сказать, в массы.
Я был бы только рад, если бы этот фреймворк продолжил развиваться. Но вы действительно поздновато вытащили его на свет. Реально, хотелось бы увидеть более мощную экосистему у этого продукта. С полными примерами по всем возможностям фреймворка, с руководством, рассмотрением всех тулзов (сборщик, генератор документации, создание тестов функциональных и модульных) и многое, многое другое, что есть в Sencha (простите, что опять вспоминаю *=)).
Может я слепой, но из всех описанных возможностей здесь и в документации проекта, я ничего нового не увидел. Все это уже есть в ExtJS. Тесты на скорость, могут вам показать те же результаты, если вы вникнете в суть ExtJS.

Я ни хочу сказать ничего плохого о фреймфорке, просто высказываю свое субъективное мнение. Я вижу в basis.js прямого конкурента ExtJS по своим возможностям, и это очень хорошо! Никакие ангулары, метеоры, бэкбоны, прототипы и иже с ними здесь рядом не стоят.
В этом фреймворке есть все, что необходимо для разработки single-page. И я бы рекомендовал его всем, кто не хочет раскашеливаться на коммерческую лицензию ExtJS, ну или кто просто хочет использовать что-то помимо него.

Кстати, каким вы видите будущее basis.js, в свете ES6 и развивающегося Dart?
На свет он вышел практически сразу после рождения и сайт был другой, и доки небольшие были и примеры. Но вот его широкий «пиар» начался действительно гораздо позже, когда уже он сформировался в текущий вид и успел засветиться в серьезных проектах.
Спасибо. Все нормально, я вас понимаю ;)

Хоть на первый взгляд многие видят сходство с extjs, на самом деле у них ничего общего.
Мощь extjs строится на готовых компонентах, и его можно назвать конструктором. Тюнить имеющие или создавать свои – занятие непростое. А без готовых компонент он практически бесполезен. К тому же он очень большой. В нем много готового, это и хорошо и плохо. Хорошо, потому что можно собрать быстро некоторое решение. Но плохо, что сложно сделать что-то свое уникальное или стилизовать.
basis.js: Компоненты которые в нем есть больше для демонстрации и для прототипирования. В каждом проекте по большей части делаются свои компоненты, это не сложно. Либо полностью заменяются шаблоны и верстка (так как представление слабосвязано с шаблоном, то ему можно подсунуть практически любой шаблон). Ну и, конечно, часто используются собственные наработки, качующие из проекта в проект. То есть в этом отношении basis является основой для создания компонент и интерфейса.
Еще, к пример, live update это не только про быстрый и удобный процесс верстки без перезагрузки страницы. Это так же адаптация представления под данные (мало данных одна верстка, много данных – другая) и такая клевая штука как темы. Еще хорошо развита работа с данными, об этом будет в следующей части. Думаю после нее отпадут вопросы о схожести с чем либо… по крайней мере с extjs точно ;)
Кстати extjs достаточно не быстрый, судя по моим экспериментам. Но мы можем сравнить, мне было бы весьма интересно.
Еще в extjs нет разделения логики и представления, нет дружелюбного сборщика (хотя может что-то поменялось?) и много чего еще. С другой стороны в basis.js тоже нет многого из того, что есть в extjs. Но у того фреймворка целая компания, куча людей, которая занимается исключительно его разработкой и развитием. Нам пока приходится только мечтать об этом :) Работа над фреймворком не является основной деятельностью, и сам он является продуктом работы над разными проектами и задачами. Так сказать собрание лучших решений, что получилось найти и различные best practices, накопленные в течении нескольких лет.
Кстати, а про какой генератор документации речь?

Насчет будущего, вижу его светлым и жизнерадостным, я оптимист ;)
basis.js старается не использовать странные стороны js и быть как можно ближе к его идеалогии. Например, года три назад мы отказали от this.inherit() (например, в Ember такой метод называется this._super()) – вызов переопределенного метода, так как поддержание это механизма дорого для производительности. Отказавшись такого хелпера, мы получили буст производительности в 2 раза (сам был в шоке). Сейчас мы пишем так
var MyClass = basis.ui.Node.subclass({
  method: function(a, b){
    basis.ui.Node.prototype.method.call(this, a, b);
    ...
  }
});

Длинно, но зато быстро. Да и сейчас редко, когда нужно переопределять методы (для этого тоже было сделано не мало).
ES6 вместе с тем нацелено решать проблемы языка. В частности эту проблему. С ES6 мы сможем писать так:
var MyClass = basis.ui.Node.subclass({
  method: function(a, b){
    super(a, b);
    ...
  }
});

А те фреймворки, что используются свой this.inherit/super/etc никакого преимущества не получат.
Еще мы смотрим на модульность в ES6. Выглядит так, что мы сможем адаптировать текущую реализацию чтобы
// помимо этого 
var Node = require('basis.ui.Node');
// работало и это
import Node from 'basis.ui';

Что касается Dart, то тут затрудняюсь ответить. Я не уверен, что получится подружить реализацию классов basis.js с идеалогией Dart, а на ней многое строится. Но я пока не копал эту тему и возможно там не все так страшно.
Я думаю, нет смысла ориентироваться на Dart. После оф. отказа представителей Mozilla, Microsoft и Apple от нативной поддержки, он просто встает в ряд со всей массой языков, компилируемых в JS, а это уже не интересно
Это же гугл, так просто не задвинут, тем более Dart это совсем не аналог CoffeeScript, как многие думают…
Я и не думаю, что Dart — аналог CoffeeScript.
Гугл не один раз закрывал свои проекты, и лично я думаю, что Dart ждет такая же участь.
Очень попахивает экстом и его ужасными фичами вида «перегрузка свойств в конструкторе» и «автосоздание вьюшек по конфигам». Тем не менее есть и много свежих идей.

Смутило, что вы удаляете элелементы, а потом добавляете в нужном порядке. Это конечно очень просто, но ресурсоёмко и теряет фокус. Я у себя пробегаюсь по спискам и трогаю элементы только если их действительно надо переместить.

Также я не разделяю эту любовь к requireJS. Какая разница будет у вас глобальная переменная или же зарегистрированный модуль, который доступен по глобальному имени? Те же глобальные переменные, но зачем-то спрятанные в недра глобальной функиции require. Относительные пути — это тоже зло, потому что при переносе модуля нужно фигурно исправлять относительные ссылки в него и из него. Лучше ссылаться ко всем модулям по глобальному имени и при переносе просто пробегаться реплейсом по всем файлам. Просто и надёжно. И если не плодить иерархию сверх меры, то вполне юзабельно.

Почитай про мою реализацию: hyoo.ru/?article=%D0%90%D1%82%D0%BE%D0%BC%D1%8B+%D0%BD%D0%B0+JS;author=Jin
Очень попахивает экстом и его ужасными фичами вида «перегрузка свойств в конструкторе» и «автосоздание вьюшек по конфигам».

Почему то все сравнивают с extjs, это прям тенденция :)
Перегрузки свойств в конструкторе нет, по крайней мере в том виде что в extjs. Есть нормализация, но это другое.
Предполагаю, что под «созданием вьюшек по конфигам» имеется ввиду фича extjs с xtype. Нет тут несколько другое. В следующей части будет рассказано про работу с данными, тогда станет понятно для чего на самом деле нужны childClass и childFactory. Данная статья вводная, объясняющая основные моменты и общий воркфлоу. Она делалась максимально простой, это обучающий материал, потому и примеры простые, и чем то напоминают другие фреймворки. Так что не пропустите следующую часть, она расставит точки на i.

Смутило, что вы удаляете элелементы, а потом добавляете в нужном порядке. Это конечно очень просто, но ресурсоёмко и теряет фокус. Я у себя пробегаюсь по спискам и трогаю элементы только если их действительно надо переместить.

Вы не верно поняли. А значит, в тексте плохое разъяснение. Не могли бы вы указать, что навело вас на такое мнение?
На самом деле, ничего не удаляется и перевставляется (если это конечно не перестроение DOM фрагмента по новому шаблону). Как вы правильно заметили это очень дорого. И по списку тоже не «бегаем». Узлы (basis.ui.Node) хорошо знают свою структуру и не делают лишних телодвижений без необходимости. Перемещения делаются перестановкой элементов, через insertBefore, только в том случае, если это действительно нужно.

Также я не разделяю эту любовь к requireJS. Какая разница будет у вас глобальная переменная или же зарегистрированный модуль, который доступен по глобальному имени? Те же глобальные переменные, но зачем-то спрятанные в недра глобальной функиции require.

Модульная система не связана никак с requirejs. Requirejs – это AMD, а в basis.js используется CommonJS. Реализация очень близкая к реализации node.js.
Имена никуда не зашиты. Неймспейсы (названия) проецируются на файловую систему. Для корневого неймспейса (например, basis – это корневой неймспейс) ассоцируется некоторый путь. К примеру, в статье basis.js подключается как bower_component/basis/src/basis.js, значит для basis базовый путь будет bower_component/basis/src/. Дальше использовался модуль basis.ui, его имя преобразуется в basis/ui.js. То есть точки заменяются на / и в конце подставляется расширение. К имени добавляется базовый путь и получаем путь к файлу bower_component/basis/src/basis/ui.js. То есть
basis.require('basis.ui');
// эквивалентно
basis.require('./bower_component/basis/src/basis/ui.js');

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

Относительные пути — это тоже зло, потому что при переносе модуля нужно фигурно исправлять относительные ссылки в него и из него.

Суть в том, что мы должны стараться ссылать только вглубь. И даже больше, только на файлы модуля и на корневые файл вложенных модулей. В этом случае, обычно, все сводится к одной единственной замене. Это было показано в разделе про реструктуризацию файлов. Но, конечно, всегда бывают исключения.
Пока получаем только плюсы от относительных путей. То, про что вы говорите, скорей всего, про ситуацию, когда много перекрестных относительных ссылок (путей). Да, это проблема и этого нельзя допускать. Если возникается такая ситуация, то скорей всего у вас не правильно организованы модули и нужно подумать как это исправить.

Почитай про мою реализацию

Если правильно понял, то это про вычисления и данные. Про это будет в следующей части руководства. Предполагаю для вас она будет куда более интересной.
Один вопрос о модульности. Можно ли догружать скрипты и CSS по требованию? Скажем, пусть на странице есть кнопка «Показать диалог», и весь код этого диалога вы подкачиваете только после того, как пользователь по ней кликнет. Будет ли это работать и в релизной версии приложения? Сможет ли сборщик определить, что скрипты диалога являются отдельным блоком, который надо отдельно скомпоновать и сжать? В прошлом именно из-за отсутствия этой возможности я отказался использовать сборщик ExtJS (Sencha CLI), поскольку даже в сжатом виде весь код моего приложения весил несколько сотен килобайт (в команде было 20 разработчиков).
ExtJS сам по себе огромный, там очень много кода и сборка получается большой.
Все модули basis.js, компоненты и шаблоны в сумме дают 389Kb (111Kb gzip). Но все модули никогда не используются, обычно доля кода фреймворка ~250Kb, тогда как размер самого приложения (достаточно большого) 800-900Kb (~250Kb в gzip). Фреймворк позволяет писать достаточно компактный код.
Сборщик basis.js собирает все в один пакет. Так проще и дешевле — скрипт загружается один раз и кешируется, при этом делается один запрос на js и один для css. Код тем не менее иниацилизируется лениво, по мере активации той или иной функциональности — потому старт достаточно быстрый.
Sign up to leave a comment.

Articles