Архитектура Light
Документ для новых контрибьюторов: как устроен фреймворк, где проходят границы между крейтами и что происходит от HTML-шаблона до кадра в окне.
Крейты воркспейса
| Крейт | Роль |
|---|---|
light-fw-core | Ядро: виртуальный DOM, реактивность, layout, paint, окно, a11y, валидация. |
light-fw-html | Парсер HTML-шаблонов: теги, атрибуты, директивы, {{ … }}, <include>. |
light-fw-macros | Процедурные макросы #[template] и #[proxy]. |
light | Мета-крейт: реэкспортирует ядро, макросы и подключённые компоненты. |
light-fw-element-form | Компонент-элемент: <checkbox>, <radio>, <select>, <option>. |
light-fw-behavior-validation | Компонент-поведение: required, :validator, @validate. |
light-fw-cli | Бинарник light: команды check, add, search, publish, … |
light-fw-cli-core | Логика CLI без привязки к терминалу: анализ, план, применение, lock. |
light-demo | Демонстрационное приложение и примеры. |
Зависимости направлены внутрь: компоненты и CLI зависят от ядра, ядро не знает
о прикладном коде. light — тонкая обёртка, чтобы приложение могло писать
use light::prelude::*; и не указывать внутренние крейты напрямую.
Компиляция шаблона
#[template("templates/app.html")]читает файл относительноCARGO_MANIFEST_DIR.light-fw-htmlразбирает разметку в деревоNode/Element/Attrи сегменты текстаLiteral/Path.light-fw-macrosобходит дерево, разрешает<include src="...">, проверяет директивы и генерирует Rust-код.- Сгенерированный код реализует
Component::render: он собираетVElementизNodeKind, стилей и обработчиков событий. #[proxy]добавляет к структуре реактивные геттеры/сеттеры иnew().
Ошибки разметки и неизвестные атрибуты становятся ошибками компиляции с указанием файла и строки. В рантайме HTML уже не парсится.
*.html ──light-fw-html──▶ AST ──light-fw-macros──▶ Rust-код Component::render
│
▼
VElement
Рантайм: от состояния до кадра
Component::render()
│
▼
VElement (новое дерево)
│
├── сравнение с предыдущим деревом (vdom::diff)
│
▼
набор операций (Op)
│
▼
Dom / виртуальное дерево окна
│
▼
layout: размеры и позиции узлов
│
▼
paint: Canvas → RGBA-буфер
│
▼
RendererBackend::present()
Основные слои light-fw-core:
vdom—VElement,NodeKind, стили, события иdiff. Ключи узлов стабильны между отрисовками; diff обновляет только изменившиеся узлы.reactive— свойстваProxy, наблюдатели и запрос перерисовки. Изменение свойства помечает окно грязным, после чего цикл окна повторяетrender → diff → layout → paint.layout— вычислениеRectдля каждого узла: колонки/строки, отступы, проценты, min/max-размеры, выравнивание, z-order и повреждённые области.window— циклwinit: события мыши/клавиатуры/размера, вызовComponent::dispatch, управление окнами, загрузка шрифта и отрисовка.window::paint— программная растеризация: прямоугольники, границы, текст черезab_glyph, фокусное кольцо и элементы форм.a11y— построение дерева AccessKit, роли, фокус, клавиатурная навигация и объявления.validation—required, пользовательские валидаторы и поиск кнопки отправки формы.
События приходят из winit, преобразуются в vdom::Event и передаются
компоненту. Компонент меняет реактивные свойства; дальнейшая перерисовка
инициируется наблюдателями, а не ручным вызовом render.
Рендеринг и RendererBackend
Растеризация не зависит от графического API. window::paint::Canvas пишет
пиксели в RGBA8-буфер, а бэкенд отвечает только за владение буфером и показ
кадра:
#![allow(unused)]
fn main() {
pub trait RendererBackend {
fn resize(&mut self, width: u32, height: u32) -> Result<()>;
fn size(&self) -> (u32, u32);
fn frame_mut(&mut self) -> &mut [u8];
fn present(&mut self) -> Result<()>;
// clear / draw_rect / draw_text по умолчанию работают через Canvas
}
}
Реализации:
SoftbufferBackend— основной путь. Хранит RGBA8-кадр, приpresentперекладывает его в0x00RRGGBBи отдаёт вsoftbuffer. Не тянетwgpu/naga, даёт меньший бинарник.WgpuBackend— альтернатива черезpixels/wgpu(фичаwgpu-backend) для сравнения и запасного пути.NullBackend— используется, когда графический бэкенд не включён: layout и ввод работают, кадр остаётся в памяти.
Если включены обе фичи, выбирается softbuffer-backend. Это зафиксировано в
docs/DESIGN_PRINCIPLES.md: по умолчанию — минимальный footprint.
CLI
light-fw-cli — тонкий слой clap над light-fw-cli-core. Ядро CLI не
зависит от терминала и запускает внешние процессы через трейт
CommandRunner, поэтому планы и ошибки тестируются с мок-раннером.
Типичный изменяющий сценарий (add, remove, update, init):
аргументы → plan_* (только чтение) → подтверждение → backup::create
→ apply_* (мутации) → cargo check → backup::restore при ошибке
Ключевые модули light-fw-cli-core:
scan/project— поиск*.html, разбор черезlight-fw-html, сопоставление тегов/атрибутов/директив со встроеннымregistry.toml.registry— статический каталог официальных компонентов, их версии, требования к ядру и фичи мета-крейта.fetch/search— разрешение компонентов: workspace →vendor/→ встроенный реестр → crates.io. Сеть скрыта заRemoteRegistry.edit— правкиCargo.tomlчерезtoml_editс сохранением форматирования: зависимости, фичи,dep:-токены.lockfile— генерацияlight.lockиз фактическогоCargo.toml.publish— топологический порядок поcargo metadata, pre-flight гейты, классификация ошибок crates.io и публикация.backup— снимки файлов перед мутацией и откат при ошибке.
Команды чтения (check, suggest, doctor, search) ничего не пишут на
диск. Команды изменения (add, remove, update, lock, init, vendor)
сначала строят план, а затем применяют его атомарно с резервной копией.
Фичи и границы
Возможности ядра включаются Cargo-фичами: элементы, окно, backend, a11y,
layout-расширения. Фича light/elements-form включает и light-fw-core, и
компонент формы; light/validation — поведение валидации. Код выключенных
возможностей не попадает в бинарник.
При добавлении публичного поля в Style, NodeKind, Interaction,
WindowConfig, VElement или Event сначала запускайте
cargo build --all-features и cargo test --all-features: компилятор и
снапшоты покажут все места, которые нужно обновить.
С чего начать
- Понять модель компонентов —
docs/COMPONENT_MODEL.md. - Написать свой компонент —
docs/COMPONENT_AUTHORING.mdиdocs/EXTERNAL_COMPONENTS.md. - Посмотреть пользовательские команды —
docs/guide.md. - Разобраться в решениях по размеру и фичам —
docs/DESIGN_PRINCIPLES.md.