UNPKG

reactant-share

Version:

A framework for building shared web applications with Reactant

82 lines (80 loc) 2.62 kB
import { actionIdentifier, applyPatches, Container, containerKey, } from 'reactant'; import { LastAction } from 'reactant-last-action'; import { HandleClientOptions } from './interfaces'; import { lastActionName, proxyServerActionName } from './constants'; import { PortDetector } from './modules/portDetector'; import { applyMethod } from './applyMethod'; export const handleClient = ({ app, transport, disposeServer, disposeClient, enablePatchesFilter, preloadedState, }: HandleClientOptions) => { if (!transport) { throw new Error(`The client transport does not exist.`); } disposeServer?.(); disposeClient?.(); const container: Container = app.instance[containerKey]; const lastAction = container.get(LastAction); const portDetector = container.get(PortDetector); portDetector.setPort({ client: app }, transport); const disposeListeners: ((() => void) | undefined)[] = []; if (preloadedState) { lastAction.sequence = preloadedState[lastAction.stateKey]._sequence; } disposeListeners.push( transport.listen(lastActionName, async (action) => { if (portDetector.disableSyncClient) return; if (action._sequence && action._sequence === lastAction.sequence + 1) { if (action._reactant === actionIdentifier) { const currentState = app.store!.getState(); const _patches = action._patches ?? []; // support subset of modules sync up const patches = enablePatchesFilter ? _patches.filter((item) => currentState[item.path[0]]) : _patches; const state = applyPatches(currentState, patches); app.store!.dispatch({ ...action, state }); } else { app.store!.dispatch(action); } lastAction.sequence = action._sequence; } else { portDetector.syncFullState({ forceSync: false }); } }) ); disposeListeners.push( transport.listen( proxyServerActionName, async ({ clientIds, portName, ...options }) => { // ignore non-specified id or name of client if ( (Array.isArray(clientIds) && portDetector.clientId && !clientIds.includes(portDetector.clientId)) || (portName && portName !== portDetector.name) ) return new Promise(() => { // never resolve }); const result = await applyMethod(app, options); return result; } ) ); disposeListeners.push(() => transport.dispose()); return () => { for (const dispose of disposeListeners) { dispose?.(); } }; };