TLDR — у $mol ( смола\мола ) реактивность, локальное хранилище, оффлайн и темы приезжают одним пакетом. Минусы есть, но они почти все про коммьюнити и тулинг, не про сам код. С ними получается жить.
Давайте начну с них(минусов), так честнее. Порядок не по важности.
Нет CDN-версии $mol — такой, чтобы подключить одной строкой <script src=...> в HTML и сразу писать UI, как с Vue. Имя класса в $mol завязано на путь в файловой системе ($mol_button лежит в mol/button/), и сборщик строит бандл из этих путей. CDN-вариант теоретически можно сделать, но придётся переписывать сборщик а энтузиаст пока не нашёлся.
Мало “серьёзных” публичных кейсов. Корпоративные приложения есть, но скрыты NDA, и в паблике остаются демки и пет-проекты. Из того, что можно показать:
-
web.giper.dev — экосистема продуктов ( аля гугл ) от автора $mol.
-
b-on-g.github.io/blitz — мой реал-тайм квиз на $mol + Giper Baza. Делал долго, полировал.
Мало встроенного тулинга. Разрабатывать на $mol приятно, но только если ты уже “прошаренный”, для новичка тяжело, не хватает возможностей в IDE. Для VS Code есть официальные расширения, но без go-to-definition и подсказок по синтаксису.
Стектрейс ошибки выглядит просто ужасно)
Стектрейс ошибки в $mol
Не знаю, можно ли это поправить, нам нужен доброволец) Попытки были, но нужно больше времени — по сути надо просто убрать шум и дублирование. При этом дебаг в браузере довольно прост, благодаря человеко-читаемым именам классов.
Что-то из тулинга я сделал сам:
-
LSP —
npm i -g view-tree-lsp@latest, плюс скаффолд приложения одной командой:npm create view-tree-lsp@latest bog/myapp -- --no-docker --no-tauri. -
tree-sitter-грамматика для view.tree.
-
Расширение для Zed на их основе — там работает go-to-definition, подсветка и прочие радости. Там 30k скачиваний, наверное боты качают всё подряд для тестов)
Великий и ужасный view.tree ( формат для декларативного описания компонент ) я минусом не считаю. Сравните свой первый опыт с jsx, например. view.tree описывает обычные js-классы — так, чтобы было проще видеть связи между компонентами и не писать boilerplate.
Плюс — удобное разделение слоёв: view.tree это абстракция над html, ts это логика, css.ts это стили. Меньше путаницы. Покажу на примере:
mol.hyoo.ru — tree-песочница
Тут базовый компонент ( по умолчанию div, но может быть чем угодно ) и его интерпретация в js-код. Методы этого класса можно перебить в .ts, или добавить новые в обоих файлах.
По сути все проблемы, описанные выше, сводятся к маленькому коммьюнити и слабому маркетингу. Ну что ж, нужны добровольцы!)
Проблема посерьёзнее — это интеграция с npm. Сейчас есть три пути для подключения библиотеки:
-
через CDN — безболезненно, но без типов,
-
скачать либу к себе в репу и закоммитить,
-
воспользоваться тулингом для воспроизводимых сборок от сообщества ( сам не пробовал, пишите в @mam_mol_разработка ).
В общем, как-то не нативно, с отторжением. Но сообщество не оставляет попыток — сейчас ведутся работы над сборщиком.
Также часто мне писали:
“На $mol нет вакансий, а если будут — не найти специалистов.”
Вакансий да, почти нет. Но можно начать новый проект в своей компании или в стартапе. И не нужен “специалист по $mol” — нужен TS-разраб, понимающий компоненты и реактивность. Онбординг 2-4 недели, это меньше, чем разобраться в чужой React-кодбазе с её Redux/Zustand/RTK/Tanstack-зоопарком.
Ещё многое в плане дизайна придётся делать с нуля, даже при том, что в $mol куча готовых компонентов. Но написав это один раз, можно будет таскать компоненты из разных приложений, как из одного ui-кита. Споры с дизайнерами обеспечены, красота требует жертв 🙂
Если дизайн не нужен, можно очень быстро собрать интерфейс из готовых кирпичиков — для админки, например.
Вот что реально требует серьёзной доработки — это документация и getting started. Мне кажется ( да и многие пишут ) это главный барьер для входа сейчас. Хорошую доку сделать довольно тяжело, но необходимо, чтобы люди быстрее и проще могли познавать, а не уходить разочарованными. Я написал свой getting started, от клонирования mam до работающего приложения с офлайном и синхронизацией. Насколько получилось, судить вам)
По поводу токсичного ореола вокруг $mol. Многие сталкивались с хейтом под постами о $mol — иногда по делу, иногда без. У нас очень ламповое и дружное комьюнити, залетайте в @giper_dev, а лучше приходите пообщаться офлайн на @piterjs. Офлайн вообще идеально, вживую невозможно быть токсиком 🙂 Так же я провожу бесплатные вводные онлайн уроки по молу, пишите.
Кажется, с минусами закончили — переходим к плюсам.
Зайду издалека. Слушал недавно react-подлодку и вспомнил, сколько на современном React приходится тюнить руками. Под каждый компонент с тяжёлым рендером — useTransition или useDeferredValue, чтобы UI не лагал на тысячах строк. И даже если сделаешь виртуализацию, это будет виртуализация только для одного этого компонента. В $mol весь рендеринг полностью виртуальный: компонентов вне вьюпорта физически не существует, эта “настройка” спрятана под капотом.
Сравните живые демо треугольника Серпинского от Карловского:
Один и тот же сценарий, одно и то же железо. Исходники обеих демок.
А вот стандартный js-framework-benchmark, где Карловский включил $mol — виртуальный рендеринг рвёт всех в щепки, потому что компонентов вне вьюпорта просто не существует.
Недавно напало вдохновение, накатал прошлую свою статью про веб-компоненты и сделал бенчмарк, где есть подсчёт количества строк кода:
Теперь про реактивность. В большинстве реактивных систем есть один и тот же edge-case: одно невалидное значение в графе вычислений может потянуть за собой соседей, которые от него формально не зависят. Покажу на Svelte, потому что их туториал даёт это потрогать руками.
Ломаем {a}, и падает {b}:
{b} в коде не зависит от {a}, но эффект каскадирует. Похожее можно поймать в большинстве топ-фреймворков, обычно решается ручным try/catch или разнесением по компонентам. При возврате {a} сумма пересчитывается.
Подскажите в комментах плиз: если разнести по разным компонентам, поведение то же? И как это решают в других фреймворках? Кейс взял из этого видео.
Теперь то же в $mol:
{b} пересчитывается независимо.
При возврате {a} пересчитывается и сумма.
В $mol эта проблема решена архитектурно. Каждый getter изолированный atom: если один падает, остальные не пересчитываются и не знают. try-catch писать не пришлось, всё само починилось без перезагрузки. Подробный разбор реактивности.
ОРП — каждый метод это точка расширения
В $mol реактивность не на уровне переменных, а на уровне методов класса. Метод-геттер автоматически становится вычисляемой реактивной ячейкой: читает данные → запоминает зависимости → пересчитывается при их изменении. Без useState, useMemo, useEffect и $derived — это спрятано под капотом.
Переиспользовать компонент — просто написать его имя в view.tree. Без копирования кода, без npm install, даже из чужой репы:
$my_dashboard $mol_pagebody /<= Chart $hyoo_crus_chart_pie<= Edit $bog_some_editor
Это работает потому, что $mol-модули адресуются по имени класса, а сборщик mam сам тянет, что нужно. Грань между «своим» и «чужим» кодом стирается.
CSS in TS
Я CSS знаю плохо, это моя боль, не хочу запоминать кучу правил. А в моле стили это просто TS-объект с типами на полях. Не знаешь свойство — тыкаешь по автодополнению, и работает) Нейронка может себя поправлять и корректировать, очень удобно.
Офлайн одной строкой
В app.meta.tree пишешь:
include \/mol/offline/install
И всё, приложение ставится как PWA и работает без сети. Манифест сборщик собирает сам.
Локализация
В view.tree ставишь @ перед строкой:
$my_page $mol_pagetitle @ \Hello, World!
view.tree транспилируется в js, и из этой строки получается метод:
/** title @ \Hello, World! */title() {return $mol_locale.text( "$my_page_title" )}
en-локаль вынимается из дефолтных значений автоматом, ключ собирается из имени компонента + имени свойства, что очень важно — идентификатор человекочитаемый и сразу указывает на место использования, как в файловой системе, так и в компоненте. Делаешь рядом page.locale=ru.json с переводами:
{ "$my_page_title": "Привет, мир!"}
И всё.
Так получается потому, что view.tree строгий dsl. По дефолту в реакте берут i18next: пишешь t('greeting.title'), ключи и словарь ведёшь сам. Для извлечения ставишь i18next-parser, он грепает исходники регекспами и ломается на динамике.
Нет конфигов
В $mol-проекте нет vite.config.ts, нет своего tsconfig у приложения. Сборщик mam знает всё по конвенциям: имя файла — тип, путь от корня — имя класса. Не нужно мучаться с конфигами.
Новый модуль = папка с парой .ts/.view.tree файлов. package.json mam генерирует сам, если его нет.
Строгая архитектура
В моле имя класса жёстко завязано на путь в файловой системе. Класс $my_app_button лежит в /my/app/button/button.ts, других вариантов нет. Захочешь назвать класс Button и положить в src/components/ui/button/index.ts? Не получится.
Кажется ограничением, но мол просто не даёт писать спагетти. Имя короткое и говорит, где смотреть. По имени класса в коде, в git log, в комменте на гитхабе ты сразу знаешь файл.
Поверх этого MVF (ModelView Fractal), паттерн декомпозиции $mol_view. Каждый компонент это и вью для родителя, и модель/контроллер для детей. Прикладная модель отдельно: $hyoo_talks_domain живёт в talks/domain/domain.ts, вью работает с её объектами, не с сырыми данными:
// talks/talk.view.tsdomain() {return this.$.$hyoo_talks_domain}chat( id ) {return this.domain().Chat( id )}
А ещё MAM не привязан к вебу. Модуль это директория с исходниками на чём угодно: view.tree, GLSL-шейдеры, CSS, JSON, файлы для других языков. Сборщику можно добавить любой язык, MAM знает только структуру директорий и зависимости между модулями.
Рендерилка изолирует падения
Любой $mol-компонент это сам себе error boundary. Exception в getter, таймаут в загрузке, что угодно — вместо этого компонента показывается заглушка. Остальной UI живой.
В реакте для того же надо обернуть всё в <ErrorBoundary> и помнить про это. В моле по дефолту.
Плюс реактивность: когда значение становится валидным, компонент сам перерендеривается без перезагрузки. Это уже было в примере с Svelte выше.
Одна кодовая база — все платформы
Один и тот же $mol-проект собирается под:
-
Web
-
Tauri (десктоп macOS/Windows/Linux, есть и iOS/Android)
-
Chrome/Firefox-расширение (MV3)
-
Telegram Mini App
Tauri-обвязка и манифест расширения уже есть в скаффолде, отдельно ничего не настраиваешь. У меня самого VK Music (bog/vk) собран и как MV3-расширение, и как зеркало на gh-pages — буквально один и тот же модуль.
Кстати, если нужен бэкенд — есть Гипер База: CRDT-синк, заточена под $mol. Это отдельная история, напишу про неё статью со сравнением с другими local-first решениями.
Почему стоит попробовать
Не из-за возраста, $mol младше React и Vue, ровесник Angular. Дело в другом: за 10 лет у $mol один мажорный релиз. У React за то же время 19 версий, у Angular 21.
|
|
$mol |
React |
Angular |
Vue |
|---|---|---|---|---|
|
Первый релиз |
2016 |
2013 |
2016 |
2014 |
|
Мажорных версий на 2026 |
1 |
19 |
21 |
3 |
|
Tree-shaking без настройки |
✅ изначально |
⭕ исключение лишнего |
⭕ препятствует, с 2022 standalone |
⭕ исключение лишнего |
|
Атомы / сигналы из коробки |
✅ изначально |
❌ только MobX и аналоги |
⭕ с 2023 |
✅ изначально |
|
Падение не валит приложение |
✅ автоматом |
⭕ ErrorBoundary с 2017 |
❌ нет |
⭕ errorCaptured вручную с 2017 |
|
Приостановка на async |
✅ автоматом на любом уровне |
⭕ Suspense, только при рендере |
❌ через RxLet вручную |
❌ только при монтировании |
|
Статическая типизация |
✅ поведение + композиция + стили (с 2020) |
❌ сторонние тайпинги |
✅ только поведение |
⭕ только поведение с 2020 |
|
Инверсия контроля |
✅ типизированные контексты |
⭕ ручные/renderProps |
✅ инъекции/контексты |
⭕ нетипизированные контексты с 2017 |
|
Разделение поведения/композиции/стилей |
✅ изначально |
❌ принципиально нет |
❌ частичное |
❌ частичное |
|
Кастомизация поведения |
✅ наследование или in-place |
⭕ ручные точки расширения |
⭕ наследование |
⭕ точки расширения с 2020 |
|
Кастомизация композиции |
✅ наследование или in-place |
⭕ ручные точки |
⭕ ручные слоты |
⭕ ручные слоты |
|
Кастомизация оформления |
✅ каскад по авто-атрибутам |
❌ ручные точки или классы |
❌ ручные точки или классы |
❌ ручные точки или классы |
|
Рендеринг только видимой области |
✅ автоматом ленивый, с 2020 полностью виртуальный |
⭕ через сторонний компонент |
⭕ через сторонний компонент |
⭕ через сторонний компонент |
|
Клиент + сервер одним кодом |
✅ изначально |
❌ другой API, готовить данные заранее |
❓ |
❓ |
Версий нет, потому что нет нужды плодить копии. Сломал API — переименуй модуль, при этом можно переиспользовать до 99% старого кода. Звучит дико, но это работает: нет lockfile-зоопарка, нет «у меня собирается, у тебя нет», нет dependabot-PR каждую неделю.
Если узнал в чём-то свою боль, приходи в @giper_dev, там разберёмся. Или потыкай песочницу, view.tree онлайн, без установки.
ссылка на оригинал статьи https://habr.com/ru/articles/1044684/