diff --git a/src/preload.ts b/src/preload.ts index d7bfc74c..beb52c1d 100644 --- a/src/preload.ts +++ b/src/preload.ts @@ -1,15 +1,20 @@ import { contextBridge } from 'electron' +import { StoreEnhancer, Action } from 'redux' +import { createComposer } from './composeWithStateSync' +import { RendererStateSyncEnhancerOptions } from './options/RendererStateSyncEnhancerOptions' +import { StateSyncOptions } from './options/StateSyncOptions' import { fetchInitialState } from './renderer/fetchInitialState' import { fetchInitialStateAsync } from './renderer/fetchInitialStateAsync' import { forwardActionToMain } from './renderer/forwardActionToMain' import { subscribeToIPCAction } from './renderer/subscribeToIPCAction' +import { preventDoubleInitialization, stopForwarding } from './utils' +import { forwardAction } from './utils/forwardAction' +import { withStoreReplacer, replaceState } from './utils/replaceState' declare global { interface Bridge { - fetchInitialState: typeof fetchInitialState - fetchInitialStateAsync: typeof fetchInitialStateAsync - forwardActionToMain: typeof forwardActionToMain - subscribeToIPCAction: typeof subscribeToIPCAction + stateSyncEnhancer: typeof stateSyncEnhancer + composeWithStateSync: typeof composeWithStateSync } interface Window { __ElectronReduxBridge: Bridge @@ -18,12 +23,41 @@ declare global { const __ElectronReduxBridge: Bridge } +const stateSyncEnhancer = (options: RendererStateSyncEnhancerOptions = {}): StoreEnhancer => ( + createStore +) => { + preventDoubleInitialization() + + return (reducer, state) => { + const initialState = options.lazyInit ? state : fetchInitialState(options) + + const store = createStore( + options.lazyInit ? withStoreReplacer(reducer) : reducer, + initialState + ) + + if (options.lazyInit) { + fetchInitialStateAsync(options, (asyncState) => { + store.dispatch(replaceState(asyncState) as never) + }) + } + + // When receiving an action from main + subscribeToIPCAction((action: Action) => store.dispatch(stopForwarding(action))) + + return forwardAction(store, forwardActionToMain, options) + } +} + +const composeWithStateSync = ( + firstFuncOrOpts: StoreEnhancer | StateSyncOptions, + ...funcs: StoreEnhancer[] +) => createComposer(stateSyncEnhancer, forwardActionToMain)(firstFuncOrOpts, ...funcs) + export const preload = (): void => { const bridge = { - fetchInitialState, - fetchInitialStateAsync, - forwardActionToMain, - subscribeToIPCAction, + stateSyncEnhancer, + composeWithStateSync, } try { diff --git a/src/renderer.ts b/src/renderer.ts index f0de1a7f..59f6ed95 100644 --- a/src/renderer.ts +++ b/src/renderer.ts @@ -1,10 +1,7 @@ -import { Action, StoreEnhancer } from 'redux' -import { forwardAction } from './utils/forwardAction' -import { replaceState, withStoreReplacer } from './utils/replaceState' +import { StoreEnhancer } from 'redux' import { RendererStateSyncEnhancerOptions } from './options/RendererStateSyncEnhancerOptions' -import { preventDoubleInitialization, stopForwarding } from './utils' +import { preventDoubleInitialization } from './utils' import { StateSyncOptions } from './options/StateSyncOptions' -import { createComposer } from './composeWithStateSync' /** * Creates new instance of renderer process redux enhancer. @@ -15,46 +12,25 @@ import { createComposer } from './composeWithStateSync' */ export const stateSyncEnhancer = ( options: RendererStateSyncEnhancerOptions = {} -): StoreEnhancer => (createStore) => { +): StoreEnhancer => { preventDoubleInitialization() - - return (reducer, state) => { - if (typeof __ElectronReduxBridge === undefined) { - throw new Error( - 'Looks like this renderer process has not been configured properly. Did you forgot to include preload script?' - ) - } - - const initialState = options.lazyInit - ? state - : __ElectronReduxBridge.fetchInitialState(options) - - const store = createStore( - options.lazyInit ? withStoreReplacer(reducer) : reducer, - initialState - ) - - if (options.lazyInit) { - __ElectronReduxBridge.fetchInitialStateAsync(options, (asyncState) => { - store.dispatch(replaceState(asyncState) as never) - }) - } - - // When receiving an action from main - __ElectronReduxBridge.subscribeToIPCAction((action: Action) => - store.dispatch(stopForwarding(action)) - ) - - return forwardAction(store, __ElectronReduxBridge.forwardActionToMain, options) - } + assertElectronReduxBridgeAvailability() + return __ElectronReduxBridge.stateSyncEnhancer(options) } // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types export const composeWithStateSync = ( firstFuncOrOpts: StoreEnhancer | StateSyncOptions, ...funcs: StoreEnhancer[] -) => - createComposer(stateSyncEnhancer, __ElectronReduxBridge.forwardActionToMain)( - firstFuncOrOpts, - ...funcs - ) +) => { + assertElectronReduxBridgeAvailability() + return __ElectronReduxBridge.composeWithStateSync(firstFuncOrOpts, ...funcs) +} + +const assertElectronReduxBridgeAvailability = () => { + if (typeof __ElectronReduxBridge === undefined) { + throw new Error( + 'Looks like this renderer process has not been configured properly. Did you forgot to include preload script?' + ) + } +}