- PVSM.RU - https://www.pvsm.ru -
Эта статья основана на опыте разработки, приложения системы конструирующей типовые Landing-page по заранее заданным в панели управления параметрами. В статье будет описано почему при разработке целевой части для разработки приложения был выбран Mithril, его свойства, преимущества и какие подводные камни можно встретить при использовании этого замечательного инструмента.
Данная статья может заинтересовать тех кто изучает использование микро-фреймворков для решения определенных задач в которых нужен удобный поддерживаемый инструментарий, с легкой и практичной архитектурой, и не нагруженной общей оболочкой. К тому же Mithril как инструмент несмотря на малый размер обладает высокой производительностью — что также является не маловажным фактором при выборе нужного инструмента разработки. Интересно?
Mithril [1] это MVC микро-фреймворк, модель отображения которого основана на Virtual DOM, который также добавляет производительности отрисовки для больших приложений, или компактных но сложных со стороны логики отрисовки виджетов. У mithril-a есть все необходимое для того чтобы называть себя полноценным фреймворком. Есть система работы с логикой — контроллеры, средства работы со связыванием данных модели, и полноценная система для работы с отрисовкой. Также он предоставляет утилиты позволяющие на низком уровне точечно управлять временем и типом перерисовки контента (например для сложных асинхронных операций), и компактные дополнения:
Все эти компоненты и составляющие позволяют разрабатывать приложения на mithril которые покроют 90% потребностей во время написания кода.
Во время проработки архитектуры, выбор был между клиентской и серверной организацией, учитывая что сама система по сути была минимально нагруженной данными, и все они были типовые, обработка всех запросов, дополнительные накладки в виде обработки шаблонов, их отдача, и время ожидания ответа клиентом — были крайне неприятными факторами, так как в наше время скорость загрузки и «мгновенной» читабельности контента крайне важна, а лишняя нагрузка на оборудования это лишняя издержка.
Поэтому вскоре мы отбросили вариант серверной реализации, и стали рассматривать варианты client-side инструментов, которые позволили бы нам решить малой кровью (и лишних потраченных нервных клеток) спектр заданных задач:
Среди рассматриваемых инструментов мы рассматривали множество библиотек вроде — Angular [2], Angular Light [3], Backbone [4], Knockout [5], React [6]. Также рассматривали не только готовые фреймворки и комплексные инструменты но и отдельно системы шаблонов, библиотеки данных и т.д.
Почему все эти варианты были отброшены во время анализа? Вот короткий обзор по списку в чем эти инструменты оказались не актуальны в выборе.
Angular и React не подходят сразу из-за своей избыточности, потому что 99% их функционала и организации в процессе не понадобятся.
Backbone — был отсеян по причине черезмерно избыточной логики, которая осталась атавизмом далеких времен, и разработка на нем поставила бы нас перед выбором практически прямого управления всем контентом, и в целом неявной структурой логики.
Knockout — отличная библиотека, но слишком большая для набора манипуляций которые в него вложены, их очень много и изначально они рассчитаны на большое количество кода для отрисовки в шаблонах (со связью с данными в логике и моделях). Управление же логикой так же как и в Backbone очень специфичное, хотя и позволяющее адекватно работать с данными и связыванием. В нашем приложении этот функционал был излишним — и было решено отказатся от этого варианта также.
Angular Light — микро аналог angular с заявленной похожей логикой, в том числе шаблонов, и «ленивыми» директивами и компонентами. От оригинальной логики и поведения директив из angular осталось не так много, упрощенная но похожая система шаблонов, система сравнения в дереве и инициализации директив — по тегу, классу, аттрибуту, и подобие $scope связывания. Хороший инструмент — но имеет довольно специфичную и не очень гибкую логику компонентного построения, и также были первоначальные трудности с пониманием ее точной работы. Этот вариант оставался запасным и рабочим до самого конца.
Когда в прицел выбора инструмента попал mithril — это уже был вполне зрелый и состоявшийся проект набора инструментов для написания приложений без излишеств, но с полноценными функциональными возможностями. У этого инструмента не было тех атавизмов или излишней шаблонной логики как у Backbone или Knockout — по сути mithril являлся небольшой оболочкой над DOM элементами, большая часть событий которых была напрямую завязана на DOM методы, с небольшим добавлением сахарка в виде Virtual DOM и привязанного к объекту логики контроллера. При этом связывание данных, и большая часть излишеств были исключены из логики — что открывало максимальную гибкость для реализации. Он собрал в себе весь минимализм и практичность которая необходима при разработке емких и расширяемых приложений. В отличие от Angular Light в нем была более прозрачная логика компонентов, более практичная и унифицированная — что позволяло легко поддерживать код, и не думать о внезапных проблемах с тонкостями архитектуры.
По умолчанию разработка компонентов на mithril-е это действительно процесс в котором правит абсолютное ничто, для большего удобства разработки можно использовать множество различных инструментов и библиотек по вашему вкусу, но считаю что есть базис который будет полезен всем кто начинает разрабатывать свои приложения на mithril.
Шаблоны
По умолчанию в Mithril как и в React довольно неудобно организованно написание узлов шаблонов, даже несмотря на систему упрощения построения DOM element query:
// Объект контейнера с атрибутом "class" элемента.
m('div', { "class": "container-class" }, [
// .. и дочерним элементом заголовка, в в котором задан статичный аттрибут через упрощение шаблона. Со значением.
m('h1[withattr="attr"]', { onclick: function(event) { /* манипуляции для события */ } }, 'Header')
]);
Особенно эта особенность ощущается если вы привыкли к использованию обычного HTML, и не хотите заморачиваться с сложностями архитектуры отображения mithril. Для этого есть специальный трансформер — MSX [7], и оболочки для него — как например самая удобная на мой взгляд babel-plugin-mjsx [8] для компилятора Babel.
Который позволяет использовать подобные конструкции которые нам так знакомы из React JSX:
<div class="container-class">
<h1 withattr="attr" onclick={ (event) => { /.../ } }>Header</h1>
</div>
По моему эту опцию (MSX) будет весьма удобно использовать таким комплектом:
gulp + browserify + babelify + msx.
Вот пример использования.
// Опции и конфигурация компилятора Babel с необходимыми нам опциями и флагами.
var Compiler = babelify.configure({
// Флаги компилятора интегрированные в babel core
optional: [
'es7.exponentiationOperator',
'es6.spec.blockScoping',
'es7.exportExtensions',
'es7.classProperties',
'es7.comprehensions',
'es7.decorators'
],
// Дополнительные кастомные плагины преобразований
plugins: [{
transformer: MSX, // Собрать MSX
position: "before" // Вызвать до основной компиляции
}]
});
gulp.task('babel-msx', function() {
browserify([ /* файлы для компиляции*/ ])
.transform(Compiler).bundle() // Интеграция промежуточного трансформера Browserify
.pipe(source('bundle.js'))
.pipe(gulp.dest('build/'));
});
Классы и ООП
В 2015 году особую популярность начал приобретать ES6, (или его расширенная черновая «сахарная» редакция ES2015 «ES7») и преобразующие его в ES5 компиляторы вроде Babel или Typescript: многим захотелось в полной мере начать использовать максимум его возможностей, включая поддержку классов, декораторов, и многое другое. Под новые реальности начали адаптироваться уже существующие фреймворки (например Angular 2.0 [9]), а также появляться — как например Aurelia [10], и поэтому использование всех возможностей, и гибкость инструментов к этим возможностям — для многих может являться важным фактором при разработке.
По умолчанию Mithril организован внутри обычного объекта, который может являться самостоятельным компонентом в архитектуре, и особые возможности организации для использования как классов — в них не реализованы, по соображениям того же минимализма, но это не значит что нельзя расширить или адаптироваться под Объектную разработку в этом инструменте.
В простейшем варианте — вам достаточно просто использовать объект компонента как экземпляр класса — например так:
/* Класс компонента */
class Component {
constructor(opts) {
/* связывание экземпляра с даными инициализации... */
this.opts = opts;
/* связать функции с областью экземпляра */
this.controller = this.controller.bind(this);
this.view = this.view.bind(this);
}
/* контроллер компонента */
controller(props) {
return {
paramOne: this.opts.paramOne
};
}
/* метод отрисовки компонента*/
view(ctrl, props, children) {
return (
<button onclick={this.method}
attr={ctrl.paramOne} />
);
}
};
/* инициализация компонента - целевым объектом компонента назначаем экземпляр */
m.mount(document.body, new Component({ paramOne: 'Hello!' }));
Это простейший способ использовать классы в Mithril — но тем не менее это все-же не идеальный вариант, в котором также стоит учитывать некоторые особенности, например не стоит хранить абсолютно все данные в экземпляре, и хранить их предположим в view — так вы не иллюзорно рискуете распрощаться с данными при последующей перерисовке — так что логику, и данные лучше держать раздельно. При этом хранить данные и манипуляции с ними в контроллере тоже не лучший выход — тогда вам придется создавать целое дерево зависимостей, в случае если придется передавать данные вглубь компонентной иерархии, что не добавит простоты и поддерживаемости и без того «ванильному» коду.
Можно например использовать при построении приложения Flux Store или любое другое хранилище которое вам удобнее всего использовать — и адаптировать его внутри компонента, тогда у вас будет четкая иерархия хранения данных, их обработки, и четкая граница абстрактных событийных операций внутри экземпляра — вроде индекса активированной вкладки, и т.д. События actions вы сможете привязать к рендеру, отрисовке, и даже создать импровизированное подобие живого цикла как в React со своими componentWillMount, componentDidMount и т.д.
Mithril основан на Virtual DOM и это одна из его отличительных особенностей, которая дает ему его скорость и производительность, но учитывая что это минималистичный фреймворк — в его системе отрисовки есть особенности которые изначально могут немного удивить разработчиков, например тех кто уже имел некоторый опыт в React. Например в Mithril вы не можете управлять перерисовкой отдельно взятого узла или компонента отдельно от всех остальных компонентов — как вы могли бы это сделать например в React. И это накладывает некоторые трудности с пониманием — поэтому стоит разобратся как работает перерисовка в Mithril.
В пользовательском доступе доступны 2 вида перерисовки:
m.startComputation/m.endComputation — методы которые позволяют работать с организацией состояния при перерисовки, буквально — они обозначают отрезки первого снимка дерева VDOM, и второго снимка, после этого оба снимка сравниваются, и после найденные изменения образуют патч — который точечно изменяет данные. Это полезно например при загрузке асинхронных данных, в этом случае вы делаете первый снимок до начала операций, и делаете последний снимок уже после того как получили результат. Из особенностей стоит отметить — что методы глобально сравнивают все дерево целиком, даже если вы вызвали их в каком-либо определенном компоненте, поэтому стоит позаботится при разработке чтобы перерисовка не повлияла на другие компоненты в дереве. Вот простой пример использования:
function asyncGetAndRedraw() {
/* Создаем снимок до целевого действия */
m.startComputation();
/* Асинхронная операция */
SomeAsyncOperation({ ...args }).then(function promised(data) {
/* обновление данных (которые используются в представлении) */
setTarget = data;
/* создание снимка после целевых действий, сравнение с первым снимком, патч представления */
m.endComputation();
});
};
m.redraw — метод для жесткой отрисовки, при вызове этого метода не делается сравнение, метод целиком перерисовывает все дерево компонентов, следует относится к этому методу с особой осторожностью — потому что при перерисовке он не учитывать уже существующие состояния компонентов.
Довольно опасная и не рекомендуемая операция, но есть моменты когда нужно вставить строку шаблонного чистого HTML, и с этим поможет метод m.trust, вот как это можно использовать.
m.render("body", [
m("div", m.trust("<p>Clean Html</p>"))
]);
В этой небольшой статье было разобрано чем может быть интересен микро-фреймворк Mithril при разработке веб-приложений, какие у него есть преимущества, сравнительный анализ с другими инструментами (по личной оценке и нуждам), а также немного сахара и заметок по использованию этого фреймворка обывателями. Из вышеизложенного считаю стоит подчеркнуть что Mithril в первую очередь предназначен для написания компактных, ёмких веб-приложений (например виджетов) которым нужна максимальная эффективность и лаконичность при разработке — вкупе с производительностью. Хотя если вы тщательно продумаете архитектуру, допишите свои реализации, методы и парочку суперклассов и декораторов как оболочек — этот инструмент не подведет вас и на крупных проектах и веб-приложениях. В статье было изложено мое мнение и наблюдения по использованию mithril — если у вас тоже есть опыт использования этой системы или тонкости которые вы для себя открыли — было бы очень интересно о них узнать. Рассчитываю что статья была интересна и полезна к прочтению.
Оффициалньый сайт. [11]
Страница фреймворка на github [1]
Полезные статьи про использование Mithril [12]
Автор: friktor
Источник [13]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/112143
Ссылки в тексте:
[1] Mithril: https://github.com/lhorie/mithril.js/
[2] Angular: https://github.com/angular/angular.js
[3] Angular Light: https://github.com/lega911/angular-light
[4] Backbone: https://github.com/jashkenas/backbone/
[5] Knockout: https://github.com/knockout/knockout
[6] React: https://github.com/facebook/react
[7] MSX: https://github.com/insin/msx
[8] babel-plugin-mjsx: https://github.com/Naddiseo/babel-plugin-mjsx
[9] Angular 2.0: https://angular.io
[10] Aurelia: http://aurelia.io/
[11] Оффициалньый сайт.: http://mithril.js.org/index.html
[12] Полезные статьи про использование Mithril: http://lhorie.github.io/mithril-blog/
[13] Источник: https://habrahabr.ru/post/272449/
Нажмите здесь для печати.