Imported from modus-bi/custom-chart (
.claude/skills/package-plugin/SKILL.md). Install upstream withnpx skills add modus-bi/custom-chart --skill package-plugin. Copyright stays with the author.
Сборка дистрибутива плагина
Суть
Дистрибутив плагина — архив <имя>.tar.gz из двух файлов: plugin.js (бандл) и
manifest.json (описание для портала). Собирается двумя командами, но между ними и вокруг них
есть проверки, без которых архив получается формально готовым и нерабочим — и узнаётся это
только при установке на портал.
Скилл — про сборку. Публикацией, загрузкой на портал и версионированием он не занимается.
Как имя класса попадает в бандл
Механика важнее порядка команд, потому что почти все отказы установки — из-за неё.
Компонент плагина на портале — один из типов CustomChart0…CustomChart40. Какой именно
слот займёт плагин, решает портал при установке, а не разработчик. Поэтому имя проходит три
состояния:
CustomChart0 имя UMD-библиотеки при сборке (webpack.config.js, output.library.name)
↓ create-plugin.js — замена в первых 1000 символах бандла
CustomChartNNN плейсхолдер в архиве
↓ портал при установке, по правилу ReplacementInTheBody из манифеста
CustomChart7 реальное имя класса в слоте портала
Отсюда два правила:
CustomChart0вwebpack.config.jsиCustomChartNNNв манифесте не переименовывать. Это не название плагина, а точки склейки; название живёт вmanifest.name.- Замена работает только в первых 1000 символах бандла. Имя библиотеки попадает туда
UMD-обёрткой, но это не гарантия на все времена: баннер, изменённый
output, другой формат библиотеки — и точка склейки уезжает за границу. Поэтому в конце обязательна проверка, что в архиве не осталосьCustomChart0.
Последнее правило исполняет портал на своей стороне: в клиентском бандле ядра ни apiVersion,
ни ReplacementInTheBody не упоминаются — манифест разбирает сервер при установке. Проверить
подстановку локально нельзя, только глазами в архиве.
Порядок
1. Убедиться, что собирать есть что
npm run typecheck && npm run lint && npm test
Красный прогон — стоп. Собирать неработающий код в дистрибутив бессмысленно: ошибка проявится
на портале, где отладки нет. Отдельно typecheck важен тем, что проверяет семь контрактных
экспортов: отсутствующий экспорт ломает не первое обращение к нему, а часть редактора целиком.
2. Подготовить манифест
create-plugin.js читает build/manifest.json. Каталог build/ не хранится в репозитории,
поэтому манифест кладётся туда перед каждой сборкой дистрибутива — образец лежит в
manifest.example.json в корне.
mkdir -p build && cp manifest.example.json build/manifest.json
mkdir -p нужен, когда сборка ещё не выполнялась: build/ в .gitignore, в свежем клоне
каталога нет, и cp упал бы.
Что в нём меняется под конкретный плагин:
| Поле | Чем заполнять |
|---|---|
name |
идентификатор плагина на портале; он же станет именем архива |
version |
версия плагина; держать в согласии с package.json |
description |
человекочитаемое описание |
apiVersion |
версия API плагинов, под которую собран плагин |
files[].path |
plugin.js — под этим именем бандл кладётся в архив |
files[].actions[].template |
CustomChartNNN — плейсхолдер, который ищет портал |
files[].actions[].replacement |
%ClassName% — подставляемое порталом реальное имя |
files[].actions[].type |
ReplacementInTheBody |
Три последних поля и path — часть контракта установки, а не настройки: менять их нельзя.
name — решение, а не факт: это идентификатор, под которым плагин будет виден на портале, и
из него получится имя архива. Если он ещё не выбран, спросить пользователя, а не
придумывать; заодно уточнить apiVersion, если она отличается от образца.
3. Собрать бандл
npm run build
Именно build, а не build:dev: последний собирает без минификации и с source map, такой
бандл в дистрибутив не годится.
Порядок шагов 2 и 3 взаимозаменяем, но сборка не должна удалять build/manifest.json.
В webpack.config.js для этого намеренно не включён output.clean — если соберёшься его
включить, положишь манифест уже после сборки, иначе он молча исчезнет.
4. Собрать архив
npm run build:plugin
Что делает create-plugin.js: создаёт temp/, копирует туда бандл под именем plugin.js и
манифест, заменяет в первых 1000 символах CustomChart0 на CustomChartNNN, пакует оба файла
в <manifest.name>.tar.gz плоско — без путей внутри архива, — и удаляет temp/.
Скрипт не возвращает ненулевой код при ошибке: он ловит исключение и печатает его в
консоль, поэтому npm run build:plugin завершается «успешно» и при отсутствующем манифесте,
и при непрочитанном бандле. Не полагаться на код возврата — проверять результат.
Побочный признак сбоя: каталог temp/ остался на месте. Он удаляется только на успешном пути.
5. Проверить архив
Обязательно, потому что предыдущий шаг об ошибках молчит.
ls -la *.tar.gz
tar -tzf <имя>.tar.gz
Ожидается ровно два файла без каталогов: plugin.js и manifest.json.
tar -xOzf <имя>.tar.gz plugin.js | head -c 300
В этом фрагменте должно быть CustomChartNNN и не должно быть CustomChart0 — иначе
замена не попала в окно первых 1000 символов, и портал не подставит имя класса.
tar -xOzf <имя>.tar.gz plugin.js | grep -c "CustomChart0" || true
Ноль — правильный ответ.
Ещё две проверки бандла:
- React не вшит. В начале бандла должно быть обращение к внешнему
React(require("React")в UMD-обёртке), а размер — единицы-десятки килобайт, не сотни. React иreact-domдаёт ядро, они вexternals; попавший в бандл React означает второй экземпляр на странице и сломанные хуки. - Имя архива совпадает с
manifest.name. Если архив называется не так, как ожидает портал, — читался не тот манифест.
6. Отчитаться
Назвать: имя и размер архива, состав, версию из манифеста, результат проверок из шага 1 и
подтверждение, что CustomChart0 в бандле не осталось. Если что-то из этого не проверялось —
сказать прямо, а не умолчать.
Грабли
| Симптом | Причина |
|---|---|
| Команда отработала, архива нет | ошибка проглочена — код возврата всегда 0; смотреть вывод и наличие temp/ |
Ошибка при копировании файла: ./build/manifest.json |
манифест не положен в build/ перед сборкой дистрибутива |
Ошибка при копировании файла: ./build/custom_chart_0.js |
бандл не собран или собран в другой каталог |
| Архив есть, портал плагин не подхватывает | в бандле остался CustomChart0 либо в манифесте сломан template/replacement |
| Архив называется не так, как ожидали | имя берётся из manifest.name, а не из package.json |
| Бандл сотни килобайт | в него попал React или библиотека отрисовки, которую следовало оставить внешней |
temp/ в рабочем дереве |
прошлая сборка упала на середине; каталог удаляется только на успешном пути |
| Плагин на портале ведёт себя как старая версия | установлен архив прошлой сборки: бандл пересобран, а архив — нет |
Чего не делать
- Не собирать дистрибутив из
build:dev-сборки. - Не переименовывать
CustomChart0вwebpack.config.jsиCustomChartNNNв манифесте — это не идентификатор плагина. - Не класть в архив ничего сверх двух файлов: портал ждёт ровно
plugin.jsиmanifest.json. - Не коммитить
build/manifest.jsonи*.tar.gz— оба каталога и маска уже в.gitignore. - Не выдавать сборку за проверенную: локально проверяется структура архива, а работоспособность плагина — только установкой на портал.