Многие сайты не должны быть SPA. Но иногда эта архитектура продиктована ограничениями. Хороший пример — сайт подкаста: статические страницы эпизодов, но есть плеер, состояние которого нужно сохранять между страницами.
Ради сохранения состояния плеера весь сайт создаётся как SPA, хотя в остальном на нём нет такой интерактивности, которая требует реактивного фреймворка. Потому что в веб-платформе нет нормальных способов решения такой задачи.
Но, кажется, способ появится. Инженеры Chromium начали прототипировать идею, предложеную группой WICG (Web Incubator Community Group) под названием Persistent Widgets. Это фрейм, который сохраняется при переходах между страницами.
Дисклеймер: это обзор раннего предложения новых функций. Синтаксис может измениться в будущем или от функций могут отказаться
При переходах между страницами DOM-дерево, состояние JS, кэш GPU, соединение WebSockets или WebRTC и состояние медиа-плеера полностью уничтожаются. Чтобы сохранить состояние, предлагается новый элемент
<persistentwidget>.<!--
Страница А:
https://example.com/index.html
(перед навигацией)
-->
<persistentwidget
id="assistant"
src="/assistant.html"
>
</persistentwidget>
<!--
Страница Б:
https://example.com/dashboard.html
(после навигации)
-->
<head>
<!--
Отрисовка заблокирована до
парсинга и обработки виджета
-->
<link
rel="expect"
href="#assistant"
blocking="render"
>
</head>
<body>
<persistentwidget
id="assistant"
src="/assistant.html"
>
</persistentwidget>
</body>
Элемент
<persistentwidget> работает как <iframe> — встраивает внешний виджет, указанный в src. Это может быть AI-чат, бот-ассистент, медиа-плеер, виджет с открытым WebSockets соединением или просто отдельная страница с контентом.При навигации между страницами внутри одного origin браузер делает следующее:
1. Не уничтожает виджет и его контекст;
2. Пока следующая страница загружается, проверяет, есть ли на ней элемент
<persistentwidget> с такими же значениями атрибутов id и src;3. Виджет и его контекст переносятся в
<persistentwidget> на следующую страницу без перезагрузки и сброса состояния JS;4. Внутри виджета выбрасывается событие
openerchange.Виджеты в
<persistentwidget> могут быть размещены только на том же origin, что и основной документ. Виджеты третьих сторон предлагается выстраивать через <iframe> в <persistentwidget>. Это одно из ограничений ради безопасности.<!-- ai-chat.html -->
<body>
<iframe
src="https://ai-chat.com/chat"
allow="microphone"
>
</iframe>
</body>
<!-- Страница «Доставка» -->
<body>
<h1>Доставка</h1>
<!-- ... -->
<persistentwidget
id="ai-chat"
src="/ai-chat.html"
>
</persistentwidget>
</body>
<!-- Страница «О нас» -->
<body>
<h1>О нас</h1>
<!-- ... -->
<persistentwidget
id="ai-chat"
src="/ai-chat.html"
>
</persistentwidget>
</body>
В качестве виджетов можно встроить
<audio> или <video> и они продолжат воспроизведение при переходе между страницами, если соблюдаются условия (same-origin, наличие <persistentwidget> с одинаковыми id и src).Ко всему прочему предлагается тесная интеграция
<persistentwidget> с BFCache и Cross-Document View Transitions, а также дополнительные JS API. Persistent Widgets находятся в стадии прототипирования и многое может измениться.#html