Последовательность запуска
После того как Web Host получает свою конфигурацию, он выполняет фиксированную последовательность инициализации до отрисовки какого-либо UI. Последовательность немного различается в зависимости от того, загружается ли Web Host как JS-модуль, забирающий страницу себе (стандартный путь через фасад), или работает внутри iframe (ручной путь без фасада), но внутренние шаги после того, как конфигурация доступна, идентичны.
Путь A — JS-модуль (стандартный, через фасад)
Это путь, который использует текущий wippy/facade. Фасад раздаёт страницу, загружающую точку входа Web Host в виде JS-модуля — module.js для режима compat или managed-layout.js для режима managed, — и модуль забирает себе всю страницу и её историю браузера.
-
Получить конфигурацию и зарегистрировать карту. Требование фасада называется
import_map;/facade/configвозвращает его какcfg.importMap. Shell загружает общий bootstrap import map и регистрирует составленную карту до импорта модулей Host. -
Импортировать модуль Host и инициализировать приложение. Shell импортирует
module.jsилиmanaged-layout.js, который предоставляетwindow.initWippyApp. Затем он вызываетinitWippyApp(appConfig, rootContainer?)с начальнойAppConfig, включаяimportMap: cfg.importMap. Рукопожатия PostMessage нет. -
Инициализация продолжается — см. Внутреннюю последовательность инициализации ниже.
Путь B — iframe (ручной, без фасада)
Этот путь используется, когда вы сами встраиваете полный хост внутрь iframe — для частичного встраивания в страницу с более сильной изоляцией. Он загружает iframe.html?waitForCustomConfig и получает конфигурацию через PostMessage SetConfig. Текущий фасад этого не создаёт; путь существует для ручных вставок.
-
Родитель подготавливает iframe. Добавьте
?waitForCustomConfigк versioned URLiframe.html. Установите обработчикmessageдо заданияiframe.src. Standalone bootstrap ожидает родительскийSetConfigдо регистрации import map и импорта модулей приложения Host. Это происходит до монтирования приложения Host. -
Родитель отвечает на
GetConfig. Дождитесь сообщенияget-configот iframe. Принимайте его, только еслиevent.originсовпадает с доверенным origin iframe, аevent.source— именноiframe.contentWindow. Затем отправьте полныйAppConfigсообщениемset-config, указав доверенный origin какtargetOrigin./facade/configсодержит настройки развертывания, но родитель должен добавить$schema,authиcontext. См. полный пример iframe. -
Web Host получает
AppConfig. Он проверяет конверт сообщения, принимаетSetConfigв iframe только от физического родительского окна и сравниваетevent.originс origin родителя, если тот доступен. В Web Fragment также требуется, чтобыfragmentIdсовпадал с собственным ID этого экземпляра. Последующие допустимые сообщенияSetConfigмогут обновлять конфигурацию этого документа. -
Инициализация продолжается — начиная с этого момента внутренний путь идентичен пути A.
Внутренняя последовательность инициализации
Как только AppConfig доступен (любым из путей), Web Host выполняет следующие шаги по порядку:
1. Инициализация хранилища Pinia.
Создаётся корневой экземпляр Pinia и регистрируются все модули хранилищ. Состояние аутентификации загружается из AppConfig.auth — токен хранится в памяти (или в cookie, если hostConfig.session.type = 'cookie'). URL окружения из AppConfig.env записываются в хранилище для использования Axios и WebSocket-клиентом.
2. Настройка Axios.
Экземпляр Axios настраивается с APP_API_URL в качестве baseURL и токеном аутентификации, подставляемым в заголовок по умолчанию. Любые axiosDefaults из конфигурации подмешиваются. Именно этот экземпляр дочерние iframe получают через proxy API.
3. Инициализация Vue Router.
Маршрутизатор создаётся с режимом истории, указанным в AppConfig.hostConfig.history ("hash" или "browser"). Регистрируются системные маршруты (/c/:id, /chat/:id, /keeper/:id и т. д.). Это статический набор — динамические маршруты монтирования добавляются на более позднем шаге.
4. Внедрение PrimeVue и темы.
PrimeVue устанавливается во Vue-приложение. Пользовательские CSS-свойства из AppConfig.theming.global и AppConfig.theming.host внедряются как переопределения :root { --key: value; } для соответствующих областей. Строки customCSS из theming.global и theming.host внедряются как теги <style>, а иконки из theming.global / theming.host регистрируются в Iconify. Этот шаг выполняется до монтирования приложения, чтобы первая отрисовка имела корректную тему.
5. Монтирование Vue-приложения.
Корневой компонент App.vue монтируется в DOM. В этот момент пользователи видят обрамление — боковую панель, панель чата, каркас раскладки, — хотя содержимое страницы может ещё загружаться.
6. Регистрация динамических маршрутов.
Приложение вызывает GET /api/public/pages/routes, чтобы получить список зарегистрированных страниц представлений. Для каждой страницы, чья запись реестра объявляет mountRoute, вызывается router.addRoute('app', ...), чтобы добавить маршрут в работающий маршрутизатор. Именованный маршрут app — родительский маршрут раскладки, оборачивающий всё содержимое.
Любой конфликт маршрутов монтирования (дублирующиеся пути, зарезервированные сегменты, некорректный синтаксис) на этом этапе устанавливает фатальную ошибку в хранилище страниц. App.vue обнаруживает её и вместо обычного UI отрисовывает полноэкранный <wippy-error> с описательным сообщением.
7. Разрешение URL.
Маршрутизатор разрешает текущий URL (из window.location в режиме browser-history или из хэша в режиме hash). Если URL совпадает с системным маршрутом или зарегистрированным маршрутом монтирования, отрисовывается соответствующая страница. Если совпадений нет, маршрутизатор откатывается к домашнему представлению чата.
8. Соединение WebSocket.
WebSocket-клиент подключается к APP_WEBSOCKET_URL, используя токен аутентификации. Начинают поступать события реального времени (входящие сообщения, обновления сессий, изменения состояния артефактов). Соединение поддерживается на протяжении всей жизни страницы.
Интерфейс AppConfig на TypeScript
Полный тип конфигурации, принимаемый и initWippyApp, и SetConfig. Обратите внимание: в AppConfig нет поля feature и поля fe_mode — fe_mode является параметром требования фасада, выбирающим точку входа модуля, а режим managed передаётся хосту через hostConfig.layout:
interface AppConfig {
$schema: 'wippy-context-2.2'
auth: AppAuthConfig
env: AppEnv
axiosDefaults?: Partial<AxiosDefaults>
routePrefix?: string
apiRoutes?: ApiRoutesOverride
tanstack?: TanstackConfig // значения по умолчанию TanStack Query (глобальные + по категориям на основе ролей)
theming: AppTheming
allowSelectModel?: boolean
hideSessionSelector?: boolean
allowAdditionalTags?: Record<string, string[]>
hostConfig: HostConfig
context: AppContext
}
interface AppAuthConfig {
token: string // Bearer-токен
expiresAt: string // отметка времени истечения в ISO 8601
}
interface AppEnv {
APP_API_URL: string
APP_AUTH_API_URL: string
APP_WEBSOCKET_URL: string
[key: string]: string | undefined
}
interface AppTheming {
global?: ThemingScope
host?: ThemingScope
children?: ThemingScope
}
interface ThemingScope {
customCSS?: string
cssVariables?: Record<string, string>
icons?: Record<string, unknown>
iconSets?: Record<string, Record<string, unknown>>
}
interface HostConfig {
session?: { type: 'non-persistent' | 'cookie' }
history?: 'browser' | 'hash'
showAdmin?: boolean
allowSelectModel?: boolean
startNavOpen?: boolean
hideNavBar?: boolean
disableRightPanel?: boolean
hideSessionSelector?: boolean
additionalNavItems?: PageApi.Page[]
stateCache?: { maxPages?: number; maxSizePerPage?: number }
allowAdditionalTags?: Record<string, string[]> // тег → разрешённые атрибуты
chat?: {
convertPasteToFile?: {
enabled: boolean
minFileSize: number
allowHtml: boolean
}
}
layout?: HostLayoutDeclaration
}
// Значения по умолчанию TanStack Query. Поле верхнего уровня (общее для хоста и потомков, как
// apiRoutes). Поведение по умолчанию (без конфигурации) — refetchOnWindowFocus: false, чтобы
// возврат по alt-tab не перезагружал загружающееся содержимое.
interface TanstackConfig {
default?: TanstackQueryOptions // переопределяет глобальные значения по умолчанию для запросов
content?: TanstackQueryOptions // отрисовка одного ресурса (page/artifact/session/entry/model/upload)
lists?: TanstackQueryOptions // запросы навигации / индексов / списков
}
// JSON-безопасное подмножество опций запросов TanStack (без функций — конфигурация в JSON).
interface TanstackQueryOptions {
refetchOnWindowFocus?: boolean
refetchOnReconnect?: boolean
refetchOnMount?: boolean
staleTime?: number
gcTime?: number
retry?: boolean | number
refetchInterval?: number | false
}
interface AppContext {
resourceId: string
resourceType: 'page' | 'artifact'
route?: string
[key: string]: unknown
}
Источники конфигурации и приоритет
Web Host разрешает конфигурацию из нескольких источников, в порядке приоритета от низшего к высшему:
- Встроенные значения по умолчанию — определены в самом бандле Web Host.
- Параметры запроса URL —
?token=<token>,?expiresAt=<timestamp>,?persistдля cookie-сессий. Полезно для прямого доступа при разработке без родительской страницы. - Аргумент
initWippyApp()— стандартный путь через фасад (JS-модуль); имеет приоритет над параметрами URL. - PostMessage
SetConfig— ручной путь через iframe без фасада, используется при наличии?waitForCustomConfig.
На практике продуктовые развёртывания всегда используют initWippyApp() (путь через фасад) или PostMessage (ручное встраивание в iframe). Параметры URL — удобство разработки для прямой загрузки хоста в браузере с токеном.
Схема запуска
Стандартный путь через фасад (JS-модуль):
shell facade получает /facade/config (требование import_map → cfg.importMap)
│
├─ получает карту Host и загружает общий bootstrap import map
├─ регистрирует составленную import map
├─ импортирует module.js / managed-layout.js
├─ модуль предоставляет window.initWippyApp
├─ shell вызывает initWippyApp({ ..., importMap: cfg.importMap }, '#app')
├─ resolveConfig() → мигрирует, нормализует config/auth/env
├─ ожидает GET /api/public/pages/routes
├─ создает Vue app и router
│ статические system routes + проверенные backend mount routes
├─ setupApp() → Pinia, Axios, PrimeVue, theme и другие providers
├─ монтирует App.vue → разрешает текущий URL
└─ компоненты запрашивают WebSocket-клиенты
См. также
- Точка входа фасада — как
AppConfigформируется и доставляется модулемwippy/facade - Многопанельная раскладка — путь запуска управляемой раскладки, обслуживаемый
managed-layout.js - Движки отрисовки — как страница отрисовывается после загрузки (srcdoc iframe против Web Fragment)
Источники Iconify
AppConfig.iconify.providers задает источник Iconify. Если поле не указано, используются онлайн-значения по умолчанию. Явно заданные значения передаются дочерним приложениям через AppConfig. См. Провайдеры Iconify.
PrimeVue и браузерные realms
Приложения импортируют PrimeVue по точным спецификаторам из закрепленной import map Host. Пересобранные приложения используют общий граф vendor PrimeVue внутри своего JavaScript realm. У каждого iframe и Web Fragment свой realm и граф модулей. Import map не добавляет стили; запрашивайте нужный CSS PrimeVue через документированные CSS-ключи Host. Уже встроенные bundle необходимо пересобрать с новой картой.
AppConfig import map
AppConfig.importMap — необязательная браузерная карта импортов верхнего уровня со стандартными полями imports и scopes.
interface AppConfig {
importMap?: {
imports?: Record<string, string>
scopes?: Record<string, Record<string, string>>
} | null
}
Для документов страниц srcdoc Host объединяет карту страницы, сгенерированные значения Host по умолчанию, затем AppConfig.importMap. У standalone- и facade-документов нет карты страницы srcdoc; они объединяют значения Host по умолчанию и AppConfig.importMap. В imports и каждом scope последнее значение совпадающего ключа заменяет предыдущее, остальные записи сохраняются. Конфигурация может заменить записи страницы или Host, включая Vue, PrimeVue и Wippy. Точный ключ соответствует одному specifier. Ключ с завершающим / задаёт префикс specifier, и целевой URL тоже должен заканчиваться на /. scopes выбирают записи по URL импортирующего модуля. Относительные целевые URL разрешаются относительно базового URL документа.
Host должен сформировать карту и зарегистрировать native import map до загрузки модулей. Позднее добавление другой карты не заменяет уже зарегистрированный ключ. Если в обновлении нет importMap, текущая настройка сохраняется. Значения null и {} очищают расширение.
Обновление import map применяется при создании документа. Оно не меняет разрешение модулей в уже существующем документе. Перезагрузите его, чтобы применить обновление; новые документы используют последнюю конфигурацию. Поддержка AppConfig.importMap и scopes в Web Fragment отложена: wippy/views 0.5.12 не гарантирует регистрацию составленной карты до загрузки модулей фрагмента.
Замена общей записи Vue, PrimeVue или Wippy может разделить идентичность модулей или сервисов между Host и дочерним кодом. Перед публикацией проверяйте интеграцию по точной опубликованной карте.
Проверенная базовая версия Web Host для прямого использования AppConfig.importMap — 1.0.64.
UI policy in 1.0.62
Web Host 1.0.62 передаёт следующие настройки чата дочерним приложениям. hostConfig относится к оболочке Web Host и никогда не входит в конфигурацию дочерних приложений. В управляемой компоновке нет встроенного чата по умолчанию. Приложения, которые полностью работают на дочернем уровне, используют поля верхнего уровня или переопределения пакета.
// Shared reader: host override, shared root field, then default.
const value = config.hostConfig?.[key] ?? config[key] ?? fallback
// Child override in package.json (no hostConfig in child payloads).
const configOverrides = {
allowSelectModel: false,
hideSessionSelector: true,
allowAdditionalTags: { svg: ['viewBox', 'preserveAspectRatio'], path: ['d'] },
}
Явные атрибуты WC имеют приоритет для конкретного экземпляра. show-selector переопределяет обратное значение hideSessionSelector. Без настройки селектор WC остаётся скрытым, а встроенный чат сохраняет видимый селектор по умолчанию. Отсутствующий атрибут наследует конфигурацию. false и {} считаются явными значениями. Карта тегов заменяет предыдущую настройку; встроенные теги сохраняются. Только успешно загруженные компоненты регистрируют атрибуты в своей области. Списки тегов берутся из AppConfig и успешно загруженных компонентов. Отдельного атрибута WC для них нет.
Существующее сообщение SetConfig обновляет конфигурацию через внутреннее событие configUpdated. Proxy API предоставляет уведомление как on('@config', callback), по аналогии с @theme и @history. Внедрённая конфигурация и публичное представление обновляются до вызова обработчиков. Отдельно собранные компоненты чата используют эту подписку и инициализируют хранилища исходной внедрённой конфигурацией. Прямое чтение config.auth поддерживается и не вызывает предупреждений; для обычных авторизованных HTTP-запросов используйте api. Новая команда PostMessage и childrenConfig не добавляются. Старый формат feature и схема 2.0 поддерживаются. Атрибуты SVG viewBox и preserveAspectRatio сохраняются, а скрипты, обработчики событий и небезопасные URL удаляются.