Обновление с v0.9
@triggery/core@0.10.0 и все остальные пакеты — аддитивный релиз.
Существующий v0.9-код компилируется и работает без изменений. Новые API
лендятся рядом со старыми; старые получают @deprecated JSDoc в v0.11
и удаляются в v1.0.
Что нового в v0.10
Заголовок раздела «Что нового в v0.10»Четыре новинки, все opt-in:
| Изменение | Влияние на твой код |
|---|---|
Inline conditions: config в createTrigger({...}) | Меньше шаблона на триггер; значения обновляются через типизированный setter |
Action channels через trigger.action(name).subscribe(cb) | Multi-subscriber обработчики actions без ручного Set + for-of fan-out |
Builder API createTrigger<S>().require(...).handle(...) | Required conditions становятся NonNullable<...> — никаких ! и if (!conditions.x) return; |
Inspector subpath @triggery/core/inspect | Opt-in factory pattern, который выносит inspector из основного бандла |
Также несколько семантических изменений:
| Поведение | v0.9 | v0.10 |
|---|---|---|
Два компонента оба делают useAction(trigger, 'x', fn) | last-mount-wins (срабатывает только последний fn) | оба fn срабатывают на каждый emit (fan-out) |
runtime.subscribeAction(...) | не было | новый метод, аддитивный (вызывается каждый subscriber) |
Два подряд вызова runtime.registerCondition(t.id, 'x', g) | stack-based — unregister top’а откатывался к предыдущему | last write wins; устаревший unregister() это no-op |
Builder-форма createTrigger<S>() (без args) | экспортировалась из @triggery/core | переехала в @triggery/core/builder subpath |
Миграция builder import — однострочное изменение, см. шаг 5 ниже.
Миграция типичного триггера
Заголовок раздела «Миграция типичного триггера»Типичный v0.9 триггер выглядит так:
Тот же триггер в v0.10:
Что ушло:
- Хранилище
let user: User | null = null;— значения живут внутри триггера - Два вызова
runtime.registerCondition—conditions:config регистрирует автоматически - Non-null assertion
conditions.user!— builder сужает тип - Guard
if (!conditions.settings) return;— то же самое new Set<(p) => void>()+for offan-out —t.action('X').subscribeделает это сам
Падение LOC на реальном движке (notifications-pipeline из репо сравнений):
181 → ~155.
Пошагово
Заголовок раздела «Пошагово»1. Начни с чистого working tree
Заголовок раздела «1. Начни с чистого working tree»Перед запуском codemod (или ручными правками) — закоммить или застэшь работу. Миграция трогает много файлов сразу; untracked-диф мешает ревью.
2. Перенеси пары let + registerCondition в config триггера
Заголовок раздела «2. Перенеси пары let + registerCondition в config триггера»Найди каждый паттерн вида:
Перепиши в:
Триггер теперь владеет ячейкой. Существующие вызовы
runtime.registerCondition для других condition keys (значения из
store или signal’ов) продолжают работать — это рекомендованный
low-level путь для externally-owned данных.
3. Перейди на action channels для fan-out
Заголовок раздела «3. Перейди на action channels для fan-out»Замени самодельный Set<callback> fan-out на trigger.action('name').
Канал кешируется по (trigger, name), так что повторные вызовы
trigger.action('showToast') возвращают тот же объект.
subscribe канала и любой runtime.registerAction(...) для того же
ключа теперь сосуществуют — оба срабатывают на каждый emit. Это
главное поведенческое изменение в v0.10; framework bindings (useAction
в React/Solid/Vue) выигрывают автоматически, потому что под капотом
переключились на subscribeAction.
4. (Опционально) Перейди на builder API чтобы убрать ! и if-return
Заголовок раздела «4. (Опционально) Перейди на builder API чтобы убрать ! и if-return»Если предпочитаешь императивную форму, включи правило
no-non-null-assertion-in-handler — оно
автоматически флагит conditions.X! (autofix убирает !).
5. Переключи builder import на @triggery/core/builder
Заголовок раздела «5. Переключи builder import на @triggery/core/builder»Если использовал chainable form createTrigger<S>().require(...).handle(...),
обнови import — builder переехал в отдельный subpath в v0.10, чтобы
приложения с только imperative createTrigger({...}) config form не платили
за builder machinery:
Imperative форма createTrigger({ id, events, handler }) остаётся
экспортируемой из @triggery/core — переехала только chainable перегрузка
без args.
6. (Опционально) Переключи inspector на factory pattern
Заголовок раздела «6. (Опционально) Переключи inspector на factory pattern»createRuntime({ inspector: true }) продолжает работать — просто
оставляет статическую ссылку на код inspector’а в основном бандле.
Factory pattern — bundle-friendly путь на будущее.
Запуск codemod
Заголовок раздела «Запуск codemod»Codemod применяет три преобразования:
- Folding пар
let + registerConditionвconditions:config + переписывание присваиваний вt.setCondition - Удаление
conditions.X!non-null assertions внутри handler’ов - Маркеры для
runtime.registerAction(..., fan-out)— миграция fan-out требует ручного шага из-за вариативности окружающегоSet + for-ofкода
В неоднозначных случаях codemod оставляет оригинальный код, дополняет его комментарием // triggery-codemod: review.
React / Solid / Vue компоненты
Заголовок раздела «React / Solid / Vue компоненты»Обычно ничего менять не нужно. useEvent, useCondition, useAction
сохраняют те же сигнатуры с одним улучшением: несколько вызовов
useAction для одной (trigger, name) пары теперь все срабатывают на
каждый emit (вместо last-mount-wins). Если код полагался на
перезапись — переключись на runtime.registerAction(trigger.id, 'name', fn).
Новый хук в React:
Это тонкая обёртка над useEffect(() => trigger.setCondition(...), [user]) —
однострочная замена для «у меня есть React state и я хочу его скормить v0.10 inline condition».
Обязательно ли мигрировать?
Нет. v0.9 паттерны работают до v1.0. v0.11 начнёт показывать @deprecated
JSDoc на старых путях, чтобы редактор их флагал, но runtime-семантика
сохраняется. v1.0 удалит deprecated пути.
Когда v0.9 перестанет поддерживаться?
v0.9 остаётся в legacy dist-tag и получает критические security-фиксы
до v1.0. Bug-фиксы, которые легко портируются, чёрри-пикаются; новые
фичи лендятся только в latest.
Что если в кодовой базе смешаны v0.9 и v0.10 паттерны? Нормально — они сосуществуют. Миграция opt-in на каждый триггер.
Бандл реально уменьшится?
Да. Main entry @triggery/core уменьшается с ~5.2 KB gz (v0.9) до
~4.2 KB gz в v0.10 (production-минификация) — благодаря тому что
DEV-warnings вырезаются через process.env.NODE_ENV и builder API
переехал в @triggery/core/builder. Если в приложении используются оба
entry’я, бандлер дедуплицирует общие хелперы и суммарная стоимость —
~3.8 KB gz.