Я разочаровался в $mol…

Может он и быстр, только экосистема нулевая. Ну и ещё система модулей кастомная, что полностью убивает любые готовые инструменты. Так что
$mol— по сути одной ногой в могиле.
Это как
nextjs: что-то дефолтное собрать легко. Делаешь шаг в сторону, и чёт в коленке дырка появляется, ходить неудобно.
$my_details $mol_view sub / <= Pager $mol_paginator value? <=> page? 0Ну и вот этот шлак писать/генерировать/ревьювить…
value?офигенно. Есть шпаргалка с мнемониками, удобными только автору. Везде автор в документации ставит пробелы вокруг всех скобок, а в СВОЁМ языке не осилил. КОНСИСТЕНТНОСТЬ.
Шпаргалка по спецсимволам view.tree
-комментарий, в код не попадает$префикс имени компонента, например$mol_button/массив, можно указать тип элементов:sub /number*словарь, ключи строки, значения любые^значение того же свойства у родителя, то естьsuper\сырая строка:message \Привет@локализуемая строка:message @ \Привет<=свойство владельца отдаётся вложенному компоненту, только чтение=>свойство вложенного компонента отдаётся владельцу, только чтение<=>свойство вложенного компонента целиком заменяется свойством владельца, двусторонняя связьпосле имени свойства: свойство принимает ключ первым аргументом,
Task_row $mol_view?после имени свойства: значение можно записать, передав аргумент,value? <=> name? \
Источник: readme $mol_view, раздел All special chars.
Был у меня сложный компонент, допустим
weather_widget. И вот в 20 местах на него наложили оверрайды. А потом я пересобрал этот widget. Что произойдёт с оверрайдами, которые знают внутреннюю структуру зависимости? Правильно, всё пойдёт крахом. И тут только две опции: 1. в 20 местах ошибки; 2. нет ошибок, зато в рантайме всё поехало.
Вот вышла
mobx2, что делать сmobx? И потом ожидаем, что там будетmobx,mobx2,mobx3,mobx4,mobx5, … Главное, что уничтожает этот подход, — иммутабельность версий. Опубликовал версию 1.2.3, всё, она иммутабельна, её нельзя отозвать, подменить и вообще хоть что-то сделать. Как мне выкатить патч? Подменятьmobx? Ты только что сломал людям проекты.
Отсутствие версий — дырища в поддержке, причём гигантская. И это при наличии автоматической установки пакетов БЕЗ ФИКСИРОВАНИЯ ВЕРСИЙ. То есть тебе на машину прилетит троян, ты даже не узнаешь. Если повторяемости сборки нет, я даже не буду рассматривать инструмент, ибо он не подходит для хоть какой-нибудь серьёзной разработки.
Большинство языков программирования основаны на модулях/файлах, и даже в java, где длиннющие имена, используются импорты. … В типичном энтерпрайз-проекте количество модулей переваливает за несколько тысяч, удачи сложить в плоский список. … Тем временем namespace в typescript уходит эксклюзивно в legacy support. А что делает
$mol? Правильно, делает namespace центром своей архитектуры.
Статических анализаторов тупо нет, везде надо ставить плагин. Zed не поддерживается. Хорошо, что в документации об этом ни слова.
^разворачивает значение указанного свойства или одноимённого свойства родителя. Если случайно у родителя и текущего компонента свойства имеют одно и то же имя (value), то привет, скрытый баг.
Весь опыт java-like ООП вышел в окно, и никого же не научил опыт проблем с наследованием и override. Ну вот был
$my_custom, затем я его пересобрал, все наследники сломались. Фреймворки должны помогать совершать МЕНЬШЕ ошибок МЕНЬШИМИ усилиями человека, а не требовать от него много скилла и внимания.
Один чел придумал свою уникальную снежинку: архитектуру, экосистему, язык разметки, компилятор и так далее. И он один нигде не ошибся и не создал проблем, по сравнению со стандартами, которые ревьювят комитеты и проверяют миллионы компаний по всему миру. Это фреймворк для одного человека, это не надёжное решение для бизнеса: для него нет публичных протестированных инструментов, поиска уязвимостей, НАСТОЯЩИХ бенчей. И формат ссылок в доке: зачем было менять мировой стандарт?
Я привёл десять тейков. Из них моему техлиду было достаточно двух, чтобы отказаться от
$mol. И я опросик среди своих коллег проводил: буквально ноль из десяти желания попробовать. Вот вы реально готовы поставить свой доход на вот это? Что не работает со всей экосистемойnpm, автоматически ставит зависимости без резолвинга версий, имеет отвратительную документацию?
Такие “разгромные” комментарии я получил от react сообщества.
Забавный факт
React самый популярный стандарт индустрии – является объективно худшим решением для фронтенда на сегодняшний день.
Я долго не мог понять чё за проблема оверрайдов такая страшная-то, все так боятся, а в $mol я её и не встречал даже В общем решил собрать и проверить эти кейсы на практике, погнали
Собрал демонстрационный репозиторий b-on-g/fragile, и деплой b-on-g.github.io/fragile, конечно же нейронкой. Это к слову о том, умеет ли ИИ в $mol
Каждое свойство это точка расширения
Синтаксис непривычный, вот и вся претензия. Когда выходил jsx были такие же предъявы. При этом забивают на то, какие проблемы решает view.tree.
View.tree даёт гибкое переопределение и встроенную композицию:
Каждое свойство в view.tree это точка расширения. Не нужно пытаться всё разнести на мелкогранулярные компоненты, иногда это просто не нужно. Упрощаем себе жизнь, переиспользование и понимание кода
Из компонента выше компилятор делает обычный js-класс:
class $my_details extends $mol_view {
page(next) {
if (next !== undefined) return next
return 0
}
Pager() {
const obj = new this.$.$mol_paginator()
obj.value = next => this.page(next)
return obj
}
sub() {
return [this.Pager()]
}
}
$mol_mem($my_details.prototype, 'page')
$mol_mem($my_details.prototype, 'Pager')
Все его методы переопределяются:
$my_app $mol_div
divs /
<= Details $my_details
page? <=> current_page? 3
page от $my_details получает значение из current_page приложения.
Стрелки показывают направление реактивного потока: <= приходит от текущего компонента, <=> двусторонняя связь, => наоборот.
В $mol переопределение свойства ничем не отличается от создания: city \Питер и заводит свойство, и подменяет. Поэтому вопрос только в том, где эта строка, у родителя или у ребенка.
Воот где собака зарыта, погнали ломать
20 оверрайдов: ломаем восемью способами
Что из этого ловится ? Во второй версии в примере базовые компоненты переделаны, наследники нет, git diff v1 v2 --stat показывает только base и widget. Вот что получилось, v1 слева, v2 справа: b-on-g.github.io/fragile.
Ловит компилятор
Владелец настраивает вложенный компонент. Это архитектурно встроенная композиция, обычный способ собирать интерфейс в $mol: плюс в том, что не нужно специально выделять и выносить компонент, если не хочется или “так правильно”
$bog_fragile_outer_page $mol_view
sub /
<= Weather $bog_fragile_outer_widget
city \Питер
В v2 виджет переименовал city в location. Страницу не трогали. Сборка:
error TS2339: Property 'city' does not exist on type '$bog_fragile_outer_widget'.
Падает, потому что view.tree генерирует не только js, но и d.ts, а в нём на каждую такую привязку лежит проверка типа:
type $bog_fragile_outer_widget__city_bog_fragile_outer_page_1 = $mol_type_enforce<
string,
ReturnType<$bog_fragile_outer_widget['city']>
>

Двадцать привязок дадут двадцать ошибок компиляции, а не тихий развал. Если бы city поменял тип, а не имя, упало бы так же.
retype: наследник задаётlimit 5, родитель сменил типlimitна строку. TS2416.rename/ts: наследник вview.tsпишетoverride heading(), родитель переименовалheading. TS4113.


Ловит только тест
rename/tree: то же переименование, но наследник задаётheadingво view.tree. Сборка зелёная, на экране «База» вместо «Наследник», падает тест наследника.

Не ловит ничего
collide/child: у наследника своё свойствоiconпод скрепку, родитель завёлiconпод колокольчик в шапке. Скрепка молча встала в шапку родителя.spread/plain: наследник перечислил содержимое родителя руками, родитель добавил шапку. Шапка молча пропала.
И два соседа, которые при тех же изменениях не ломаются: collide/named (свойство названо attach_icon) и spread/keep (содержимое родителя взято через ^).


А что с ^
Тут смешались две вещи. ^ без имени это просто вызов родителя, super:
$bog_fragile_spread_keep $bog_fragile_spread_base
sub /
^
<= Extra $mol_view
sub / \Ещё
sub(){
return [...(super.sub()), (this.Extra())];
}
Он не прячет баг, а лечит «забытый super», это spread/keep выше.
А вот случайное совпадение имён с родителем существует, и ^ тут ни при чём. Это collide/child.
Почему не стреляло
Выходит, что про view.tree критик прав. В ts есть слово override, и если его написать, переименование в родителе ловится. Во view.tree различия между «объявляю новое свойство» и «переопределяю родительское» пока нет. Я спросил об этом Дмитрия Карловского, автора $mol:
Во view.tree этого пока что нет. Проблема реальна, но за 10 лет не стреляла. Да и даже в ts директива override опциональна, появилась не сразу, да и все на неё забивают.
Почему не стреляла ? Совпадение имён ловится тем, что свойства называют по смыслу. У меня в PR в piterjs на ревью попросили переименовать свойство icon в upload_icon, ровно ради этого. Случай collide/named в репо о том же. На практике за десять лет не стреляло ни совпадение имён, ни переименование под оверрайдом.
Есть ли смысл тогда придираться ? Кажется что нет.
Лирическое отступление про определение свойств
Мы думали сделать, чтобы отличалось, например можно новые свойства добавлять через <= title
$my_card $mol_view
sub /
<= Title $mol_view
sub / <= title \Карточка
Здесь <= title \Карточка заводит в $my_card новое свойство title. А тут ниже только переопределение:
$my_card_news $my_card
title \Новости
Если автор $my_card переименует title, компилятор скажет, что у наследника переопределять нечего. Так мы получили бы тот же override, что в ts, без нового спецсимвола.
Может быть, внесём это изменение, кажется, это должно упростить понимание и внести ясность в этот вопрос
Наследовать необязательно
Забытый super в его классическом виде, когда наследник не вызвал инициализацию родителя, в $mol встречается редко: у компонентов нет жизненного цикла вроде setup() или componentDidMount, который надо не забыть вызвать. Свойство это функция от состояния, переопределил и вернул значение.
А когда компоненту нужно добавить поведение, его вообще не наследуют, а подключают сбоку. Для этого есть два механизма.
Плагин это компонент без своего DOM-элемента, он работает на элементе владельца, как директива в Angular. Так подключаются горячие клавиши, жесты, навигация стрелками. Вот кусок $mol_search:
$mol_search $mol_pop
plugins /$mol_plugin
^
<= Hotkey $mol_hotkey
key * escape? <=> clear? null
Плагины родителя не теряются, их забирает ^.
Призрак, $mol_ghost, оборачивает другой компонент и подмешивает свою логику в его DOM-элемент, не создавая лишнего узла. Так сделаны $mol_drag и $mol_drop: любой компонент становится перетаскиваемым, если передать его в Sub, и наследовать для этого ничего не нужно.
Про «фреймворк должен помогать совершать меньше ошибок» я согласен целиком, только посчитать стоит, где их совершить проще. В реакте есть статья с двенадцатью сценариями «нужен ли здесь useEffect», и в каждом можно выбрать не тот вариант. Я переписал все двенадцать на $mol: Нужен ли здесь useEffect? Выбирать там приходится из двух вариантов. Либо это действие пользователя, событие. Либо это мемоизированная ячейка, которая считается из других ячеек, и событием она быть не может. Перепутать их сложно.
npm, версии и трояны
Экосистема
Стоит признать, что нормальной интеграции с npm сейчас нет, это то, что должно исправиться в новом сборщике ( как и много чего еще, сборщик – худшая часть $mol ). Интеграция есть, но не очень нормальная)
В ноде пакет берётся через $node.anyname, во фронт он попадает либо через require, где сборщик ставит его сам без привязки версии, либо копируем .min.js из node_modules c сохранением версии. По большей части npm в $mol не нужен, все основные компоненты и возможности есть в самом $mol. (роутер, стор, запросы, локализация, виртуализация, и куча всего еще )
Раздел доки про npm-пакеты
Как подключить пакет, расписано в доке: Установка, раздел «Подключение npm-пакетов».

Версии
mobx → mobx2 → mobx3 …
Правда в том, что $mol живёт на одной ветке. Новая мажорная версия это новый модуль с новым именем, старый остаётся и может стать адаптером к новому. Патч приезжает всем сразу, при следующей сборке.
Цена подхода тоже понятна: рядом могут жить $mol_foo и $mol_foo2. За десять лет в mol/ таких пар набралось восемь: book и book2, object и object2, range и range2, hotkey, image, syntax, crypto, а у log версий три.
Главное, что даёт такой подход: обновляться не страшно. Ломать совместимость внутри одного имени не принято, для ломающих изменений делаем новый модуль, а-ля $mol_book2, и переходим на него, когда удобно. А если кто-то всё же сломает старое имя, чаще всего это поймает компилятор, а не пользователь.
Lock-файл
В типичном приложении на $mol npm зависимостей нет, а значит:
нет дерева из сотен транзитивных пакетов, где версия любого может уехать;
в собранное приложение не уезжает ни одного
npm-пакета; ( спасибо кэп !)нет возможности атаки через npm!
Зависимости из git по умолчанию нигде не фиксируются. Можно зафиксировать тегом или коммитом, а штатная фиксация паков появится только с новым сборщиком, например когда мы сможем опубликовать бандл как npm-пакет. Поинт валидный, но далеко не такой критичный, как было озвучено.
Теперь, когда нужен npm. В корне MAM в .npmrc стоит package-lock=false, так с марта 2019 года. Когда код просит npm-пакет, $node_autoinstall зовёт npm install <имя> без версии, а в сгенерированный package.json бандла зависимость пишется как "*". Повторяемой сборки в том смысле, в каком её даёт package-lock.json, при автоустановке нет.
Про троян. С сентября 2026 в том же .npmrc стоит ignore-scripts=true, то есть postinstall пакета при автоустановке не выполнится, а это основной путь, которым троян из npm попадает на машину.
Как зафиксировать версию npm-пакета
А версию можно зафиксировать, так делает yuf. У модуля yuf/fflate есть папка .npm с обычным package.json, где версия fflate прописана явно. Оттуда esbuild собирает пакет в один файл, deploy в fflate.meta.tree кладёт его рядом с бандлом, а код грузит его через $mol_import.script. В точку-папку сборщик MAM не лезет, автоустановки там нет, это обычный npm со всеми его инструментами, и версия в нём фиксируется как обычно. Lock-файл там тоже работает как обычно. Выглядит и ощущается костыльно, это точно должно быть исправлено в новом сборщике.
Модули и IDE
FQN вместо импортов и плоский список модулей
Вот тут тоже очевидное недопонимание $mol поощряет группировку по доменам! и именно поэтому получаются НЕглубокие иерархии
Тысячи модулей в одну кучу никто не складывает. $mol_button_minor лежит в mol/button/minor/: домен button, внутри его вариации. Вложенность небольшая, потому что всё имя целиком попадает в бандл и его желательно держать коротким. А глубокое дерево папок или широкое неглубокое это шило на мыло, нужный модуль в обоих случаях находится поиском по тексту, а не прогулкой по папкам.
FQN. Импортов нет, сборщик сам строит граф зависимостей по именам, которые встретил в коде, и кладёт в бандл только их. ИМЕННО поэтому в $mol маленькие бандлы даже без tree-shaking !
Вместо того чтобы вырезать лишнее - $mol не собирает мусор. Это решение на уровне архитектуры, и в этом весь $mol, так у него во всём. Каждое техническое решение основано на техническом анализе, а не на том, что “так принято”.
Критик прав, что namespace действительно устарел. Флаг erasableSyntaxOnly и запуск ts в ноде через вырезание типов неймспейсы с рантайм-кодом не поддерживают. Для $mol это не проблема, т.к. ts всё равно собирает сборщик, но понятно что нужно что-то думать. В новом сборщике планируется поддержать импорты и неймспейсы.
Нет поддержки IDE
Для ts всё работает из коробки, потому что view.tree превращается в d.ts и ide видит обычные классы. Для view.tree есть языковой сервер view-tree-lsp и расширение для Zed, которое я и написал) Подсветка, переход к определению, подсказки свойств.
Есть поддержка в VS Code: в корне MAM лежит папка .vscode, и при открытии склонированного mam VS Code сам предлагает поставить рекомендованные расширения из .vscode/extensions.json, там же сниппеты.
В документации про это отдельная страница Инструменты, разделы Zed и VS Code.

Фреймворк одного человека, плохая документация, странный сайт
Сейчас две доки, официальная и моя smalljs.
Есть еще претензия про “привычный вид урла”, её не очень понимаю. Ну непривычный, зато работает хорошо, вон на gh pages отлично работает без костылей. А сео и пререндер я сверху накинул уже, для ботов. Человек получает удобный быстрый интерфейс, а бот нужные ему вещи.
Автор у $mol один, и bus factor это реальный риск для бизнеса. Но: фреймворку десять лет, за это время у него был один мажорный релиз, а код открыт и компактен. Вы можете прочитать его целиком, что для фреймворка уровня реакта нереально. Есть второй мейнтейнер.
А на «уникальную снежинку» вместо стандартов лучше всех ответил Сергей, мейнтейнер:
В этом весь смысл: наплевать на кривые стандарты, сделать свои прямые. Надо свою моду диктовать.
Про «ненастоящие бенчи»: в общепринятом бенчмарке js-framework-benchmark $mol нет. Бенчмарк рендерит таблицу на тысячи строк разом, а в $mol полная виртуализация рендеринга: строк вне экрана физически не существует. Метрика с моделью рендеринга как бы несовместима*. Но по факту какая разница, зачем выводить пользователю на страницу миллионы строк, если видеть он будет от силы 50 на экране ? Зачем это писькомерство когда пользователь будет страдать ? Вот можно же сделать хорошо в общем случае, алгоритмы же все учили, всех заставляют искать общее решение, а не частное. И это даёт результат, мы там обгоняем даже vanilla js)

Итого
Версии. Слабая интеграция с
npm. Решается пока только руками:npmс версией и lock-файлом в папке.npm, свой выпуск по тегу. Штатно это закроет новый сборщик.Объявление и переопределение во view.tree не различаются. Переименование в родителе ловит только тест, совпадение имён с родителем не ловит ничего (
rename/treeиcollide). За десять лет это не стреляло, и от этого спасает привычка называть свойства по смыслу.
Остальное:
оверрайды у владельца ловит компилятор, двадцать мест дадут двадцать ошибок, а не тихий развал;
чужих пакетов в собранном приложении нет, атаковать пользователя через цепочку поставок не через что;
Синтаксис и формат ссылок это вопрос привычки, а не реальный аргумент.
Репозиторий: b-on-g/fragile, деплой: b-on-g.github.io/fragile.
А если после всего этого захотелось потрогать $mol самому, начните с установки: за пару команд у вас будет рабочее приложение, и дальше вы сами решите, разочароваться в нём или нет)
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.