К содержанию

Навигация

Как обновить проект

Обновление проекта — переход на новый выпуск по журналу изменений: механические замены делает инструмент, остальное — человек. Здесь — порядок обновления и разбор записей журнала на примерах.

Как обновить проект

Обновление — это переход проекта с одного выпуска Framework на другой (вместе с пакетами продуктов, если они подключены). Страница описывает порядок перехода, инструмент sf-upgrade и работу с ИИ.

Порядок

  1. Узнайте, на каком выпуске проект сейчас (см. ниже).
  2. Выберите новый выпуск Framework и запишите его идентификатор и полный коммит, а для подключения с CDN — версию пакета npm @simai-studio/ui этого выпуска; до запроса с CDN убедитесь, что npm её уже показывает (см. Пакет npm). Если подключён пакет продукта, возьмите его сборку, квитанция которой называет этот выпуск Framework.
  3. Прогоните sf-upgrade по проекту и исправьте всё, что он нашёл (Инструмент sf-upgrade). Исходники после --apply рассчитаны на новый выпуск, поэтому замены и новую поставку выкладывайте вместе.
  4. Замените поставку целиком в тестовом окружении: свою копию distr/ — каталогом нового выпуска, а при подключении с CDN — версию пакета во всех трёх адресах.
  5. Проверьте основные страницы на мобильной и настольной ширине, в обеих темах, Network и Console; на страницах со Smart-компонентами — пустой SF.deprecations.list().
  6. Запишите новый идентификатор выпуска, его полный коммит, версию пакета npm (при подключении с CDN) и квитанции пакетов.
  7. Перенесите в рабочее окружение те же проверенные файлы.

Как узнать текущий выпуск проекта. Страница не сообщает свой выпуск: идентификатора выпуска в поставке нет. Выпуск определяют так:

  • по файлу блокировки проекта (см. Версии: как закрепить выпуск), если он есть;

  • по адресу поставки: при подключении с CDN в адресе стоит версия пакета npm, и npm view @simai-studio/ui@<версия> simai называет её выпуск и коммит; записи о выпусках (contracts/releases/ в ui) называют коммит каждого выпуска в поле runtime_sources.core.commit;

  • для своей копии без записи — сравнением файлов: копия distr/ совпадает с каталогом distr/ в коммите выпуска репозитория ui. Совпавший целиком выпуск — текущий. Сравнить копию с выпуском можно так; пустой вывод diff означает совпадение:

    Bash
    mkdir -p /tmp/release
    git -C simai-ui archive <коммит выпуска> distr | tar -x -C /tmp/release
    diff -r /tmp/release/distr public/assets/simai-framework/ui/distr
    

Откат — тоже целиком: вернуть прежний выпуск Framework вместе с прежними сборками пакетов, не смешивая файлы разных выпусков.

Инструмент sf-upgrade

scripts/sf-upgrade.mjs в репозитории ui-source читает журнал и ищет устаревшие имена в исходниках проекта: HTML, PHP и Blade, Twig, Vue, JavaScript и TypeScript, CSS и SCSS, Markdown, JSON. Инструмент и журнал лежат в открытом репозитории simai/ui-source; в поставке ui их нет. Ревизию ui-source, из которой собран выпуск, называет поле build_inputs.source.commit записи о выпуске (см. Выпуск и запись о выпуске).

Инструмент и журнал берут из ревизии ui-source целевого выпуска — того, на который проект переходит: git checkout <build_inputs.source.commit>. Более новый журнал может назвать каноническое имя, которого в целевом выпуске ещё нет, и --apply записал бы в проект имя, которое этот выпуск не знает. Для выпуска ui-106d5901f8c3 это ревизия 3029d8abda3899f055d91e1599e1c19a969e4369.

Инструменту нужен только Node.js: зависимостей у него нет, устанавливать ничего не нужно.

Bash
node scripts/sf-upgrade.mjs ../my-product                      # только отчёт
node scripts/sf-upgrade.mjs ../my-product --apply              # механические замены
node scripts/sf-upgrade.mjs ../my-product --json               # отчёт для ИИ и скриптов
node scripts/sf-upgrade.mjs ../my-product --since 2026-10-01   # только записи с этой даты
node scripts/sf-upgrade.mjs ../my-product --journal ./journal.json   # другой файл журнала
Параметр Что делает
<папка проекта> Обязателен: каталог, который просматривается вместе со всеми вложенными
--apply Выполняет механические замены и переписывает файлы
--json Печатает отчёт одним JSON-документом; с --apply в нём applied: true
--since ГГГГ-ММ-ДД Берёт только записи, устаревшие в этот день или позже (deprecated_on)
--journal <путь> Читает журнал из указанного файла вместо contracts/changes/journal.json рядом с инструментом

Параметры сочетаются: --apply --json делает замены и печатает отчёт.

Отчёт --json — один JSON-объект:

JSON
{
  "summary": {"project": "/abs/my-product", "files": 214, "findings": 3,
              "mechanical": 2, "applied": false, "manual": 1},
  "findings": [
    {"file": "templates/cart.html", "line": 12, "record": "attribute-type-to-appearance",
     "stage": "compat", "from": "type", "to": "appearance", "mechanical": true}
  ],
  "manual": [
    {"id": "…", "summary": "…", "manual": "…", "examples": {"before": "…", "after": "…"},
     "places": ["templates/cart.html:40 …"]}
  ]
}
Поле Что в нём
summary Просмотренный каталог, число файлов, число находок, из них механических, были ли замены (applied) и число записей с ручной работой (manual)
findings Каждая находка: файл относительно каталога проекта, строка, запись журнала, её этап, устаревшее и каноническое имя (to равно null, если замены нет), механическая ли замена. С --apply выполненные замены остаются в списке, а summary.applied равно true
manual Каждая запись с ручной работой: id, summary, инструкция manual, пример examples и места places в виде файл:строка имя

Коды завершения: 0 — находок нет или с --apply остались только выполненные механические замены, 1 — остались находки (без --apply — любые, с --apply — ручные), 2 — не указана папка проекта.

Какие папки пропускаются: node_modules, vendor, .git, dist, build, build_production, storage, .artifacts. Папка distr не пропускается. Если проект хранит свою копию поставки внутри проверяемого каталога (например, public/assets/simai-framework/ui/distr/), инструмент находит устаревшие имена и в файлах самого Framework, а --apply их переписывает. Запускайте инструмент на каталогах с исходниками проекта или держите копию поставки вне проверяемого каталога.

  • Без --apply инструмент только сообщает: файл, строку, устаревшее и каноническое имя, запись журнала. Пока находки остаются, он завершается с кодом 1, поэтому его можно ставить в проверки проекта.
  • С --apply он сам делает механические замены: атрибут, значение, событие, класс, токен, утилиту. Если в теге уже есть каноническое имя, устаревшее просто удаляется — каноническое действует и во время работы страницы.
  • Инструмент читает файлы .html, .htm, .php (в том числе .blade.php), .twig, .vue, .js, .mjs, .ts, .jsx, .tsx, .css, .scss, .md и .json. Прежнее имя события заменяется в любой строке в одинарных, двойных или обратных кавычках в любом из этих файлов, в том числе в JavaScript, Vue и Blade: addEventListener('sf-range-slider-change', …) становится addEventListener('change', …).
  • Где инструмент ищет каждое имя: атрибут компонента — только в открывающем теге этого компонента, значение — в открывающем теге <sf-…>, событие — в кавычках в любой строке, класс и токен — как отдельное слово в любом месте. Поэтому находки бывают и в .json и .md, например ключ "type"; проверьте их перед --apply.
  • Остальное он выводит списком для ручной работы — с инструкцией и примером из записи.
  • Инструкцию manual механической записи инструмент не выводит. Она печатается только для ручных мест. Если у механической записи есть поле manual, прочитайте его в журнале сами: оно описывает, чем замена меняет поведение (пример — в Запись с механической заменой).
  • --since ограничивает проверку записями, устаревшими в указанный день или позже. В записи о выпуске даты нет. Если неизвестно, на каком выпуске проект и когда он обновлялся, запускайте инструмент без --since: он проверит все записи журнала.
  • Инструмент читает и удалённые записи, поэтому обновить можно проект, отставший на любое число выпусков.
  • Компонент пакета приходит на страницу только из объявленного пакета. Если запись журнала переносит компонент в пакет (to равно SF_BOOT_CONFIG.packages.<имя>), в проекте есть его тег, а этот пакет нигде не объявлен (packages: {<имя>: …}, packages.<имя> = … или вызов SF.RuleLoader.registerPackage('<имя>', …)), инструмент сообщает об этом как о ручной работе и называет, что добавить: объявление пакета (см. Пакеты компонентов). Так перенесены в пакет продукта larena (исходник — simai/larena-ui) четыре элемента: sf-table, sf-data-view, sf-property-view и sf-admin-menu; запись журнала — component-larena-package-move. В поставке ui их нет; на странице они работают, только если она объявила пакет larena, например SF_BOOT_CONFIG.packages.larena = {base: '/assets/larena/5f33ba576aebde377d5195ec71836eb4430aa84d/smart'} (путь — по правилу из Пакеты компонентов), и подключила его сборку, квитанция которой называет выпуск Framework на странице. Проект без Larena берёт сборку из выпуска simai/larena-ui (см. Пакет larena для проекта без Larena).

После ручных правок инструмент запускают снова и повторяют, пока он ничего не находит: ручная правка одного места может открыть следующую механическую замену, например значение атрибута, который правили вручную.

Проект обновлён, когда выполнены три условия:

  1. sf-upgrade ничего не находит;
  2. проверки проекта проходят;
  3. SF.deprecations.list() пуст на затронутых страницах.

Обновление с помощью ИИ

Журнал устроен так, чтобы по нему мог работать ИИ, не угадывая соответствий. ИИ получает три вещи:

  1. отчёт sf-upgrade --json — найденные места и список ручной работы;
  2. записи журнала, на которые этот отчёт ссылается;
  3. проверки самого продукта.

Правила для ИИ:

  • сначала выполняются механические замены через --apply, затем каждое ручное место — строго по инструкции и примеру из его записи;
  • соответствие, которого нет в журнале, придумывать нельзя;
  • работа закончена при тех же трёх условиях, что и у человека (Инструмент sf-upgrade).

Общие правила работы с ИИ — см. Работа с ИИ.

Пример: запись журнала и её применение

Этот раздел показывает на одном примере, как запись журнала превращается в правку проекта. Записи бывают двух видов: с механической заменой и с ручной работой.

Запись с механической заменой

Возьмём запись attribute-type-to-appearance из Журнал изменений: rewrite равно rename-attribute, у sf-button атрибут type заменяется на appearance.

Пусть в шаблоне проекта есть такая разметка:

HTML
<sf-button type="outline" text="Отмена"></sf-button>

Что происходит на каждом шаге:

  1. На странице. Пока запись на этапе совместимости, кнопка работает: Smart-компонент читает type как appearance. SF.deprecations.list() показывает строку с компонентом sf-button, устаревшим именем type и каноническим appearance.

  2. Отчёт. node scripts/sf-upgrade.mjs ../my-product сообщает файл, строку, замену type → appearance и запись attribute-type-to-appearance, отмечая её как механическую.

  3. Замена. С --apply инструмент сам переписывает разметку:

    HTML
    <sf-button appearance="outline" text="Отмена"></sf-button>
    

    Если в теге уже были оба атрибута, type удаляется, а appearance остаётся.

  4. Проверка. Повторный запуск sf-upgrade ничего не находит, список SF.deprecations.list() на этой странице пуст.

Что важно заметить: ни человек, ни ИИ не выбирают новое имя сами — его даёт поле to записи.

Одна запись — несколько имён. Запись event-change-aliases заменяет на change все прежние имена события изменения: sf-button-group-change у sf-button-group, sf-datepicker-change и sf-change у sf-datepicker, sf-dropdown:change у sf-dropdown, sf-range-slider-change и onSliderChange у sf-range-slider. У sf-button-group методы select() и clear() тоже отправляют change, как и прежнее имя. Пока запись на этапе совместимости, прежние имена приходят вместе с change, поэтому код на прежних именах работает до замены. У sf-datepicker прежнее sf-change несёт другой detail: все данные компонента, а не состав change (см. События).

Механическая замена может менять поведение. Запись event-change-aliases механически заменяет прежние имена события изменения на change, в том числе sf-range-slider-change у sf-range-slider. Её поле manual предупреждает: sf-range-slider-change приходит и при установке значения из кода, а change — только при действии человека (см. Соглашение change). Код, которому нужно событие после установки значения из кода, после замены вызывает свой обработчик сам. sf-upgrade --apply это предупреждение не печатает (см. Инструмент sf-upgrade), поэтому поле manual каждой применённой записи читают в журнале.

Запись с ручной работой

Если в записи rewrite равно manual, механической замены нет: устаревшее имя нельзя заменить одним каноническим без решения автора проекта.

  1. Отчёт. sf-upgrade находит места с устаревшим именем, но не меняет их даже с --apply. Каждое такое место попадает в список ручной работы вместе с полем manual и примером examples из записи.
  2. Правка. Человек или ИИ правит каждое место строго по инструкции из manual.
  3. Проверка. Проект обновлён при тех же трёх условиях (Инструмент sf-upgrade).

Изменение поведения (запись с kind равным behaviour) и переименование свойства JavaScript (kind равен property) sf-upgrade не ищет. Для таких изменений запись журнала описывает в поле manual, что проверить и как поправить; места находит человек или ИИ по полям from и to, а результат подтверждают проверки проекта.

Связь с другими частями

Поиск по документации

Введите минимум 2 символа

    Настройки

    Тема
    Размер шрифта
    Ширина страницы