electron-redux
Advanced tools
Comparing version 2.0.0-alpha.4 to 2.0.0-alpha.5
@@ -6,2 +6,12 @@ import { ipcMain, webContents, ipcRenderer } from 'electron'; | ||
var IPCEvents; | ||
(function (IPCEvents) { | ||
IPCEvents["INIT_STATE"] = "electron-redux.INIT_STATE"; | ||
IPCEvents["INIT_STATE_ASYNC"] = "electron-redux.INIT_STATE_ASYNC"; | ||
IPCEvents["ACTION"] = "electron-redux.ACTION"; | ||
})(IPCEvents || (IPCEvents = {})); | ||
const defaultMainOptions = {}; | ||
function _defineProperty(obj, key, value) { | ||
@@ -99,8 +109,10 @@ if (key in obj) { | ||
const middleware = store => { | ||
ipcMain.handle('electron-redux.INIT_STATE', async () => { | ||
// Serialize the initial state using custom replacer | ||
return JSON.stringify(store.getState(), options.replacer); | ||
ipcMain.handle(IPCEvents.INIT_STATE_ASYNC, async () => { | ||
return JSON.stringify(store.getState(), options.serializer); | ||
}); | ||
ipcMain.on(IPCEvents.INIT_STATE, event => { | ||
event.returnValue = JSON.stringify(store.getState(), options.serializer); | ||
}); // When receiving an action from a renderer | ||
ipcMain.on('electron-redux.ACTION', (event, action) => { | ||
ipcMain.on(IPCEvents.ACTION, (event, action) => { | ||
const localAction = stopForwarding(action); | ||
@@ -112,3 +124,3 @@ store.dispatch(localAction); // Forward it to all of the other renderers | ||
if (contents.id !== event.sender.id && !contents.getURL().startsWith('devtools://')) { | ||
contents.send('electron-redux.ACTION', localAction); | ||
contents.send(IPCEvents.ACTION, localAction); | ||
} | ||
@@ -122,3 +134,3 @@ }); | ||
if (contents.getURL().startsWith('devtools://')) return; | ||
contents.send('electron-redux.ACTION', action); | ||
contents.send(IPCEvents.ACTION, action); | ||
}); | ||
@@ -133,4 +145,2 @@ } | ||
} | ||
const defaultOptions = {}; | ||
/** | ||
@@ -142,3 +152,4 @@ * Creates new instance of main process redux enhancer. | ||
const mainStateSyncEnhancer = (options = defaultOptions) => createStore => { | ||
const mainStateSyncEnhancer = (options = defaultMainOptions) => createStore => { | ||
preventDoubleInitialization(); | ||
@@ -151,13 +162,20 @@ const middleware = createMiddleware(options); | ||
async function fetchInitialState(options, callback) { | ||
function fetchInitialState(options) { | ||
const state = ipcRenderer.sendSync(IPCEvents.INIT_STATE); | ||
return JSON.parse(state, options.deserializer); | ||
} | ||
async function fetchInitialStateAsync(options, callback) { | ||
// Electron will throw an error if there isn't a handler for the channel. | ||
// We catch it so that we can throw a more useful error | ||
const state = await ipcRenderer.invoke('electron-redux.INIT_STATE').catch(error => { | ||
try { | ||
const state = await ipcRenderer.invoke(IPCEvents.INIT_STATE_ASYNC); | ||
callback(JSON.parse(state, options.deserializer)); | ||
} catch (error) { | ||
console.warn(error); | ||
throw new Error('No Redux store found in main process. Did you use the mainStateSyncEnhancer in the MAIN process?'); | ||
}); // We do some fancy hydration on certain types like Map and Set. | ||
// See also `freeze` | ||
} | ||
} | ||
callback(JSON.parse(state, options.reviver)); | ||
} | ||
const REPLACE_STATE = 'electron-redux.REPLACE_STATE'; | ||
/** | ||
@@ -169,5 +187,4 @@ * Creates an action that will replace the current state with the provided | ||
const replaceState = state => ({ | ||
type: 'electron-redux.REPLACE_STATE', | ||
type: REPLACE_STATE, | ||
payload: state, | ||
@@ -178,6 +195,5 @@ meta: { | ||
}); | ||
const wrapReducer = reducer => (state, action) => { | ||
const withStoreReplacer = reducer => (state, action) => { | ||
switch (action.type) { | ||
case 'electron-redux.REPLACE_STATE': | ||
case REPLACE_STATE: | ||
return action.payload; | ||
@@ -190,5 +206,7 @@ | ||
const defaultRendererOptions = {}; | ||
const middleware = store => { | ||
// When receiving an action from main | ||
ipcRenderer.on('electron-redux.ACTION', (_, action) => { | ||
ipcRenderer.on(IPCEvents.ACTION, (_, action) => { | ||
store.dispatch(stopForwarding(action)); | ||
@@ -198,3 +216,3 @@ }); | ||
if (validateAction(action)) { | ||
ipcRenderer.send('electron-redux.ACTION', action); | ||
ipcRenderer.send(IPCEvents.ACTION, action); | ||
} | ||
@@ -205,4 +223,2 @@ | ||
}; | ||
const defaultOptions$1 = {}; | ||
/** | ||
@@ -216,13 +232,14 @@ * Creates new instance of renderer process redux enhancer. | ||
const rendererStateSyncEnhancer = (options = defaultOptions$1) => createStore => { | ||
const rendererStateSyncEnhancer = (options = defaultRendererOptions) => createStore => { | ||
preventDoubleInitialization(); | ||
return (reducer, state) => { | ||
const store = createStore(wrapReducer(reducer), // TODO: this needs some ❤️ | ||
state, applyMiddleware(middleware)); // This is the reason we need to be an enhancer, rather than a middleware. | ||
// We use this (along with the wrapReducer function above) to dispatch an | ||
// action that initializes the store without needing to fetch it synchronously. | ||
const initialState = options.lazyInit ? state : fetchInitialState(options); | ||
const store = createStore(options.lazyInit ? withStoreReplacer(reducer) : reducer, initialState, applyMiddleware(middleware)); | ||
fetchInitialState(options, state => { | ||
store.dispatch(replaceState(state)); | ||
}); // TODO: this needs some ❤️ | ||
if (options.lazyInit) { | ||
fetchInitialStateAsync(options, asyncState => { | ||
store.dispatch(replaceState(asyncState)); | ||
}); | ||
} // TODO: this needs some ❤️ | ||
// XXX: TypeScript is dumb. If you return the call to createStore | ||
@@ -232,2 +249,3 @@ // immediately it's fine, but even assigning it to a constant and returning | ||
return store; // TODO: this needs some ❤️ | ||
@@ -234,0 +252,0 @@ }; |
@@ -15,2 +15,12 @@ 'use strict'; | ||
var IPCEvents; | ||
(function (IPCEvents) { | ||
IPCEvents["INIT_STATE"] = "electron-redux.INIT_STATE"; | ||
IPCEvents["INIT_STATE_ASYNC"] = "electron-redux.INIT_STATE_ASYNC"; | ||
IPCEvents["ACTION"] = "electron-redux.ACTION"; | ||
})(IPCEvents || (IPCEvents = {})); | ||
const defaultMainOptions = {}; | ||
function _defineProperty(obj, key, value) { | ||
@@ -108,8 +118,10 @@ if (key in obj) { | ||
const middleware = store => { | ||
electron.ipcMain.handle('electron-redux.INIT_STATE', async () => { | ||
// Serialize the initial state using custom replacer | ||
return JSON.stringify(store.getState(), options.replacer); | ||
electron.ipcMain.handle(IPCEvents.INIT_STATE_ASYNC, async () => { | ||
return JSON.stringify(store.getState(), options.serializer); | ||
}); | ||
electron.ipcMain.on(IPCEvents.INIT_STATE, event => { | ||
event.returnValue = JSON.stringify(store.getState(), options.serializer); | ||
}); // When receiving an action from a renderer | ||
electron.ipcMain.on('electron-redux.ACTION', (event, action) => { | ||
electron.ipcMain.on(IPCEvents.ACTION, (event, action) => { | ||
const localAction = stopForwarding(action); | ||
@@ -121,3 +133,3 @@ store.dispatch(localAction); // Forward it to all of the other renderers | ||
if (contents.id !== event.sender.id && !contents.getURL().startsWith('devtools://')) { | ||
contents.send('electron-redux.ACTION', localAction); | ||
contents.send(IPCEvents.ACTION, localAction); | ||
} | ||
@@ -131,3 +143,3 @@ }); | ||
if (contents.getURL().startsWith('devtools://')) return; | ||
contents.send('electron-redux.ACTION', action); | ||
contents.send(IPCEvents.ACTION, action); | ||
}); | ||
@@ -142,4 +154,2 @@ } | ||
} | ||
const defaultOptions = {}; | ||
/** | ||
@@ -151,3 +161,4 @@ * Creates new instance of main process redux enhancer. | ||
const mainStateSyncEnhancer = (options = defaultOptions) => createStore => { | ||
const mainStateSyncEnhancer = (options = defaultMainOptions) => createStore => { | ||
preventDoubleInitialization(); | ||
@@ -160,13 +171,20 @@ const middleware = createMiddleware(options); | ||
async function fetchInitialState(options, callback) { | ||
function fetchInitialState(options) { | ||
const state = electron.ipcRenderer.sendSync(IPCEvents.INIT_STATE); | ||
return JSON.parse(state, options.deserializer); | ||
} | ||
async function fetchInitialStateAsync(options, callback) { | ||
// Electron will throw an error if there isn't a handler for the channel. | ||
// We catch it so that we can throw a more useful error | ||
const state = await electron.ipcRenderer.invoke('electron-redux.INIT_STATE').catch(error => { | ||
try { | ||
const state = await electron.ipcRenderer.invoke(IPCEvents.INIT_STATE_ASYNC); | ||
callback(JSON.parse(state, options.deserializer)); | ||
} catch (error) { | ||
console.warn(error); | ||
throw new Error('No Redux store found in main process. Did you use the mainStateSyncEnhancer in the MAIN process?'); | ||
}); // We do some fancy hydration on certain types like Map and Set. | ||
// See also `freeze` | ||
} | ||
} | ||
callback(JSON.parse(state, options.reviver)); | ||
} | ||
const REPLACE_STATE = 'electron-redux.REPLACE_STATE'; | ||
/** | ||
@@ -178,5 +196,4 @@ * Creates an action that will replace the current state with the provided | ||
const replaceState = state => ({ | ||
type: 'electron-redux.REPLACE_STATE', | ||
type: REPLACE_STATE, | ||
payload: state, | ||
@@ -187,6 +204,5 @@ meta: { | ||
}); | ||
const wrapReducer = reducer => (state, action) => { | ||
const withStoreReplacer = reducer => (state, action) => { | ||
switch (action.type) { | ||
case 'electron-redux.REPLACE_STATE': | ||
case REPLACE_STATE: | ||
return action.payload; | ||
@@ -199,5 +215,7 @@ | ||
const defaultRendererOptions = {}; | ||
const middleware = store => { | ||
// When receiving an action from main | ||
electron.ipcRenderer.on('electron-redux.ACTION', (_, action) => { | ||
electron.ipcRenderer.on(IPCEvents.ACTION, (_, action) => { | ||
store.dispatch(stopForwarding(action)); | ||
@@ -207,3 +225,3 @@ }); | ||
if (validateAction(action)) { | ||
electron.ipcRenderer.send('electron-redux.ACTION', action); | ||
electron.ipcRenderer.send(IPCEvents.ACTION, action); | ||
} | ||
@@ -214,4 +232,2 @@ | ||
}; | ||
const defaultOptions$1 = {}; | ||
/** | ||
@@ -225,13 +241,14 @@ * Creates new instance of renderer process redux enhancer. | ||
const rendererStateSyncEnhancer = (options = defaultOptions$1) => createStore => { | ||
const rendererStateSyncEnhancer = (options = defaultRendererOptions) => createStore => { | ||
preventDoubleInitialization(); | ||
return (reducer, state) => { | ||
const store = createStore(wrapReducer(reducer), // TODO: this needs some ❤️ | ||
state, redux.applyMiddleware(middleware)); // This is the reason we need to be an enhancer, rather than a middleware. | ||
// We use this (along with the wrapReducer function above) to dispatch an | ||
// action that initializes the store without needing to fetch it synchronously. | ||
const initialState = options.lazyInit ? state : fetchInitialState(options); | ||
const store = createStore(options.lazyInit ? withStoreReplacer(reducer) : reducer, initialState, redux.applyMiddleware(middleware)); | ||
fetchInitialState(options, state => { | ||
store.dispatch(replaceState(state)); | ||
}); // TODO: this needs some ❤️ | ||
if (options.lazyInit) { | ||
fetchInitialStateAsync(options, asyncState => { | ||
store.dispatch(replaceState(asyncState)); | ||
}); | ||
} // TODO: this needs some ❤️ | ||
// XXX: TypeScript is dumb. If you return the call to createStore | ||
@@ -241,2 +258,3 @@ // immediately it's fine, but even assigning it to a constant and returning | ||
return store; // TODO: this needs some ❤️ | ||
@@ -243,0 +261,0 @@ }; |
{ | ||
"name": "electron-redux", | ||
"version": "2.0.0-alpha.4", | ||
"version": "2.0.0-alpha.5", | ||
"description": "Redux & Electron: Make sure all your stores are on the same page", | ||
@@ -97,4 +97,3 @@ "repository": "https://github.com/klarna/electron-redux.git", | ||
"sourceDirectory": "tests/e2e/renderer" | ||
}, | ||
"commonDistDirectory": "e2e_dist" | ||
} | ||
}, | ||
@@ -101,0 +100,0 @@ "husky": { |
import { StoreEnhancer } from 'redux'; | ||
export declare type MainStateSyncEnhancerOptions = { | ||
/** | ||
* Custom store serializaton function. This function is called for each member of the object. | ||
* If a member contains nested objects, | ||
* the nested objects are transformed before the parent object is. | ||
*/ | ||
replacer?: (this: unknown, key: string, value: unknown) => unknown; | ||
}; | ||
import { MainStateSyncEnhancerOptions } from './options/MainStateSyncEnhancerOptions'; | ||
/** | ||
@@ -11,0 +4,0 @@ * Creates new instance of main process redux enhancer. |
import { StoreEnhancer } from 'redux'; | ||
export declare type RendererStateSyncEnhancerOptions = { | ||
/** | ||
* Custom function used during de-serialization of the redux store to transform the object. | ||
* This function is called for each member of the object. If a member contains nested objects, | ||
* the nested objects are transformed before the parent object is. | ||
*/ | ||
reviver?: (this: unknown, key: string, value: unknown) => unknown; | ||
}; | ||
/** | ||
@@ -17,2 +9,2 @@ * Creates new instance of renderer process redux enhancer. | ||
*/ | ||
export declare const rendererStateSyncEnhancer: (options?: RendererStateSyncEnhancerOptions) => StoreEnhancer; | ||
export declare const rendererStateSyncEnhancer: (options?: import("./options/RendererStateSyncEnhancerOptions").RendererStateSyncEnhancerOptions) => StoreEnhancer; |
import { FluxStandardAction } from './isFSA'; | ||
declare type ActionMeta = { | ||
export declare type ActionMeta = { | ||
scope?: 'local' | string; | ||
@@ -20,2 +20,1 @@ }; | ||
export declare const validateAction: (action: any) => action is FluxStandardAction<ActionMeta>; | ||
export {}; |
No README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
Found 1 instance in 1 package
30526
19
518
0
94