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. Версия 1: WebSocket + Node + файловая система. Один WebSocket на вкладку. Без SW.
  2. Версия 2: Service Worker + MessagePort. UI → MessagePort → SW → WebSocket.
  3. Версия 3: Версия 2 + GlobalStorage внутри SW и внутри вкладки. Бизнес-логика тоже исполняется внутри.

Следующий шаг

«Следующий шаг — это сюда вот вставить business logic runner и вставить два global storage ещё, чтобы внутри таба работал global storage и внутри service worker работал global storage.»

То есть бизнес-логика и storage становятся частью архитектуры внутри Service Worker.

🎓 Источники

См. также