Сборка пакета .portalpart
Сборка пакета .portalpart
WebPart пишутся на C# и упаковываются в ZIP-архив .portalpart (manifest + DLL + CSS + опционально JS).
Быстрый старт
cd packages/webpart-examples/hello-widget./build.sh# → dist/hello-widget.portalpartСкрипт использует Docker-образ mcr.microsoft.com/dotnet/sdk:10.0 для dotnet publish.
Шаблон нового WebPart
cd backenddotnet new install ./templates/portal-webpartdotnet new portal-webpart -n my-widget -o ../packages/my-widgetСоздайте manifest.json (см. manifest.md), стили в dist/main.css, при необходимости клиентский код в dist/main.js, затем соберите ZIP по аналогии с build.sh в примере.
Структура пакета
my-widget.portalpart (ZIP)├── manifest.json└── dist/ ├── MyWidget.dll ├── main.css └── main.js ← опционально, см. PortalWebPartClients в manifest.mdУстановка: Админка → WebPart → загрузить файл.
Обновление WebPart после изменений в коде
Изменения в исходниках (*.cs, dist/main.css, dist/main.js) не попадают в портал автоматически. Работающий экземпляр берёт DLL, CSS и JS из установленного пакета в хранилище (S3), а не из каталога packages/.
Цикл обновления
- Внесите изменения в C#-код и/или
dist/main.css,dist/main.js. - Увеличьте версию в
manifest.json(semver, например1.0.1→1.0.2). Это важно для сброса кэша CSS/JS (см. ниже). - Соберите пакет:
Окно терминала cd packages/webpart-examples/my-widget./build.sh# или локально: dotnet publish … && zip (см. build.sh в примере) - Переустановите
.portalpart:- Админка → WebPart — загрузите ZIP с тем же
id(старый пакет будет заменён); - или POST
/api/v1/webparts/packages(multipart, полеpackage, права администратора).
- Админка → WebPart — загрузите ZIP с тем же
- Обновите страницу в браузере с очисткой кэша (
Cmd+Shift+R/Ctrl+Shift+R) или откройте страницу в новой вкладке.
Повторная загрузка с тем же id в manifest.json удаляет предыдущий пакет, выгружает старую DLL из памяти API и регистрирует новую версию. Настройки WebPart на страницах (Property Pane) сохраняются — меняется только код и ассеты.
Что обновляется при переустановке
| Компонент | Где хранится | Поведение при переустановке |
|---|---|---|
| C# / HTML (SSR) | dist/*.dll в S3 | Новая DLL подхватывается при следующем render/action |
| CSS | dist/main.v{version}.css в S3 | Новый путь + ?v=… в URL definition |
| JS | dist/main.v{version}.js в S3 | То же; bind вызывается заново после render |
Кэш CSS/JS (автоматически)
При сборке build.sh вызывает scripts/stage-versioned-assets.py:
- Переименовывает
dist/main.css→dist/main.v{version}.css(и JS аналогично). - Обновляет
styles/scriptsвmanifest.jsonвнутри ZIP.
При установке пакета backend дополнительно добавляет ?v={version} к URL в definition:
/api/v1/webparts/assets/demo.my-widget/dist/main.v1.0.2.css?v=1.0.2Фронтенд (webPartLoader.js) кэширует ассеты по (manifestKey, pathname, version) и снимает старые <style> / <script> при смене версии. Ответ API для URL с ?v= — Cache-Control: public, max-age=31536000, immutable.
В исходниках указывайте обычные имена (dist/main.css); версионирование имён — только на этапе сборки ZIP.
Кэш и типичные проблемы
«Изменил код, на странице старый вид»
- Пакет не переустановлен — выполните шаги 3–4 выше.
- Браузер закэшировал CSS — жёсткое обновление страницы.
- Версия в
manifest.jsonне изменилась — URL ассетов остаётся прежним; увеличьтеversion.
«Работает HTML, но не стили / не JS»
- Проверьте, что
styles/scriptsуказаны вmanifest.jsonи файлы попали в ZIP (unzip -l *.portalpart). - CSS/JS должны быть в пакете, не в
frontend/public/.
«После обновления JS не срабатывает»
- Ключ в
PortalWebPartClients[…]должен совпадать сidв манифесте. bindвызывается после заменыinnerHTML— не вешайте обработчики только при первой загрузке страницы.
Локальная разработка без Docker
Если build.sh недоступен (нет Docker):
cd packages/webpart-examples/my-widgetdotnet publish MyWidget.csproj -c Release -o dist/stage/dist/publishmkdir -p dist/stage/distcp dist/stage/dist/publish/MyWidget.dll dist/stage/dist/MyWidget.dllcp manifest.json dist/stage/manifest.jsoncp dist/main.css dist/stage/dist/main.css# main.js — при наличииpython3 ../scripts/stage-versioned-assets.py dist/stagecd dist/stage && zip -r ../my-widget.portalpart manifest.json dist/См. также backend/templates/README.md.