Почему $mol?
- вторник, 9 июня 2026 г. в 00:00:18
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_page body / <= Chart $hyoo_crus_chart_pie <= Edit $bog_some_editor
Это работает потому, что $mol-модули адресуются по имени класса, а сборщик mam сам тянет, что нужно. Грань между «своим» и «чужим» кодом стирается.
Я CSS знаю плохо, это моя боль, не хочу запоминать кучу правил. А в моле стили это просто TS-объект с типами на полях. Не знаешь свойство — тыкаешь по автодополнению, и работает) Нейронка может себя поправлять и корректировать, очень удобно.
В app.meta.tree пишешь:
include \/mol/offline/install
И всё, приложение ставится как PWA и работает без сети. Манифест сборщик собирает сам.
В view.tree ставишь @ перед строкой:
$my_page $mol_page title @ \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.ts domain() { 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 онлайн, без установки.