Service Worker как прокси Metacom
Service Worker держит один WebSocket-транспорт на все вкладки PWA. Каждая вкладка ходит в Service Worker через MessagePort, а тот форвардит на Metacom-сервер.
Зачем
Если у пользователя 10 вкладок твоей PWA — без Service Worker откроется 10 WebSocket к серверу. С Service Worker — один общий канал.
Архитектура
Tab 1 ─┐
Tab 2 ─┼─→ MessagePort ─→ Service Worker ─→ WebSocket ─→ Metacom server
Tab N ─┘
- Каждая вкладка общается с Service Worker через
MessagePort. - Service Worker держит один
WebSocketTransport. - Service Worker мультиплексирует запросы по вкладкам.
Metacom Proxy
Класс в клиентском Metacom, который перехватывает все RPC-вызовы из вкладки и форвардит их через MessagePort.
// В Service Worker:
const proxy = new MetacomProxy(new WebSocketTransport(url));
self.addEventListener('message', (e) => proxy.handle(e));
// В вкладке:
const api = await metacom.load('chat');
await api.chat.send('hello'); // на самом деле идёт в SW
UI не знает, что между ним и сервером ещё один прыжок.
Адресация ответов
Service Worker должен знать, какой ответ в какую вкладку отправить. Решение — каждая вкладка регистрируется при подключении, получает ID. RPC-пакеты тегаются tab ID.
Один WebSocket — две задачи
- Connection efficiency — экономия серверных connections.
- Single source of truth — состояние подписок и кешей в одном месте, не дублируется в вкладках.
Service Worker умирает
Браузер убивает Service Worker через 30 сек — 5 мин после закрытия последней вкладки. Открытый WebSocket держит SW живым, потому что есть активность.
Прослойка composability
Metacom Proxy композирует WebSocket Transport. Когда нет Service Worker (старые браузеры) — Metacom работает напрямую. С Service Worker — добавляется промежуточный слой без изменения API клиента.
Цитата
«Зачем нужна эта прослойка? Для того чтобы закладки открывались-закрывались, а при этом один WebSocket транспорт у нас был. Чтобы запрос RPC, который пришёл именно с закладки номер 1 или с закладки номер 5, попал в WebSocket транспорт.»
Эволюция PWA
- Версия 1: WebSocket + Node + файловая система. Один WebSocket на вкладку. Без SW.
- Версия 2: Service Worker + MessagePort. UI → MessagePort → SW → WebSocket.
- Версия 3: Версия 2 + GlobalStorage внутри SW и внутри вкладки. Бизнес-логика тоже исполняется внутри.
Следующий шаг
«Следующий шаг — это сюда вот вставить business logic runner и вставить два global storage ещё, чтобы внутри таба работал global storage и внутри service worker работал global storage.»
То есть бизнес-логика и storage становятся частью архитектуры внутри Service Worker.
🎓 Источники
- 🎓 Развитие PWA от простого чата до Local-first · 2026-02-06
- 🎓 Что могут Service Worker — Local-First подход · 2025-12-09
- 🎓 PWA Progressive Web App — Websocket, local-first, offline-first · 2025-08-04