Make Store initialization independent of module order
Summary: Changed some imports, and again the Flipper initialisation broke. Refactored the store initialization to create nowhere module local constants, which prevents generally against module loading issues, making it possible to load all code first, and then intialise things through the `init()` method, which should make Flipper initialisation a lot more robust to changes Reviewed By: passy Differential Revision: D29233603 fbshipit-source-id: 322cb87cba23228b1d7a88634b7b3995e27cc277
This commit is contained in:
committed by
Facebook GitHub Bot
parent
806dd63f68
commit
6fb28df855
@@ -12,11 +12,11 @@ import {
|
|||||||
getAllPromisesForQueryingDevices,
|
getAllPromisesForQueryingDevices,
|
||||||
} from '../iOSDevice';
|
} from '../iOSDevice';
|
||||||
import configureStore from 'redux-mock-store';
|
import configureStore from 'redux-mock-store';
|
||||||
import reducers, {State} from '../../reducers/index';
|
import {State, createRootReducer} from '../../reducers/index';
|
||||||
import {getInstance} from '../../fb-stubs/Logger';
|
import {getInstance} from '../../fb-stubs/Logger';
|
||||||
|
|
||||||
const mockStore = configureStore<State, {}>([])(
|
const mockStore = configureStore<State, {}>([])(
|
||||||
reducers(undefined, {type: 'INIT'}),
|
createRootReducer()(undefined, {type: 'INIT'}),
|
||||||
);
|
);
|
||||||
const logger = getInstance();
|
const logger = getInstance();
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import {BundledPluginDetails, InstalledPluginDetails} from 'flipper-plugin-lib';
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import {remote} from 'electron';
|
import {remote} from 'electron';
|
||||||
import {FlipperPlugin} from '../../plugin';
|
import {FlipperPlugin} from '../../plugin';
|
||||||
import reducers, {State} from '../../reducers/index';
|
import {createRootReducer, State} from '../../reducers/index';
|
||||||
import {getInstance} from '../../fb-stubs/Logger';
|
import {getInstance} from '../../fb-stubs/Logger';
|
||||||
import configureStore from 'redux-mock-store';
|
import configureStore from 'redux-mock-store';
|
||||||
import {TEST_PASSING_GK, TEST_FAILING_GK} from '../../fb-stubs/GK';
|
import {TEST_PASSING_GK, TEST_FAILING_GK} from '../../fb-stubs/GK';
|
||||||
@@ -33,7 +33,7 @@ import loadDynamicPlugins from '../../utils/loadDynamicPlugins';
|
|||||||
const loadDynamicPluginsMock = mocked(loadDynamicPlugins);
|
const loadDynamicPluginsMock = mocked(loadDynamicPlugins);
|
||||||
|
|
||||||
const mockStore = configureStore<State, {}>([])(
|
const mockStore = configureStore<State, {}>([])(
|
||||||
reducers(undefined, {type: 'INIT'}),
|
createRootReducer()(undefined, {type: 'INIT'}),
|
||||||
);
|
);
|
||||||
const logger = getInstance();
|
const logger = getInstance();
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import {initLauncherHooks} from './utils/launcher';
|
|||||||
import {setPersistor} from './utils/persistor';
|
import {setPersistor} from './utils/persistor';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import {store} from './store';
|
import {getStore} from './store';
|
||||||
import {cache} from '@emotion/css';
|
import {cache} from '@emotion/css';
|
||||||
import {CacheProvider} from '@emotion/react';
|
import {CacheProvider} from '@emotion/react';
|
||||||
import {enableMapSet} from 'immer';
|
import {enableMapSet} from 'immer';
|
||||||
@@ -59,8 +59,6 @@ if (process.env.NODE_ENV === 'development' && os.platform() === 'darwin') {
|
|||||||
global.electronRequire('mac-ca');
|
global.electronRequire('mac-ca');
|
||||||
}
|
}
|
||||||
|
|
||||||
const logger = initLogger(store);
|
|
||||||
|
|
||||||
enableMapSet();
|
enableMapSet();
|
||||||
|
|
||||||
GK.init();
|
GK.init();
|
||||||
@@ -127,7 +125,7 @@ class AppFrame extends React.Component<
|
|||||||
</Layout.Container>
|
</Layout.Container>
|
||||||
) : (
|
) : (
|
||||||
<_LoggerContext.Provider value={logger}>
|
<_LoggerContext.Provider value={logger}>
|
||||||
<Provider store={store}>
|
<Provider store={getStore()}>
|
||||||
<CacheProvider value={cache}>
|
<CacheProvider value={cache}>
|
||||||
<TooltipProvider>
|
<TooltipProvider>
|
||||||
<PopoverProvider>
|
<PopoverProvider>
|
||||||
@@ -181,6 +179,18 @@ function setProcessState(store: Store) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
|
const store = getStore();
|
||||||
|
const logger = initLogger(store);
|
||||||
|
|
||||||
|
// rehydrate app state before exposing init
|
||||||
|
const persistor = persistStore(store, undefined, () => {
|
||||||
|
// Make sure process state is set before dispatchers run
|
||||||
|
setProcessState(store);
|
||||||
|
dispatcher(store, logger);
|
||||||
|
});
|
||||||
|
|
||||||
|
setPersistor(persistor);
|
||||||
|
|
||||||
initializeFlipperLibImplementation(store, logger);
|
initializeFlipperLibImplementation(store, logger);
|
||||||
_setGlobalInteractionReporter((r) => {
|
_setGlobalInteractionReporter((r) => {
|
||||||
logger.track('usage', 'interaction', r);
|
logger.track('usage', 'interaction', r);
|
||||||
@@ -213,18 +223,13 @@ function init() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// rehydrate app state before exposing init
|
setImmediate(() => {
|
||||||
const persistor = persistStore(store, undefined, () => {
|
// make sure all modules are loaded
|
||||||
// Make sure process state is set before dispatchers run
|
// @ts-ignore
|
||||||
setProcessState(store);
|
window.flipperInit = init;
|
||||||
dispatcher(store, logger);
|
|
||||||
// make init function callable from outside
|
|
||||||
window.Flipper.init = init;
|
|
||||||
window.dispatchEvent(new Event('flipper-store-ready'));
|
window.dispatchEvent(new Event('flipper-store-ready'));
|
||||||
});
|
});
|
||||||
|
|
||||||
setPersistor(persistor);
|
|
||||||
|
|
||||||
const CodeBlock = styled(Input.TextArea)({
|
const CodeBlock = styled(Input.TextArea)({
|
||||||
...theme.monospace,
|
...theme.monospace,
|
||||||
color: theme.textColorSecondary,
|
color: theme.textColorSecondary,
|
||||||
|
|||||||
@@ -140,82 +140,84 @@ const launcherSettingsStorage = new LauncherSettingsStorage(
|
|||||||
resolve(launcherConfigDir(), 'flipper-launcher.toml'),
|
resolve(launcherConfigDir(), 'flipper-launcher.toml'),
|
||||||
);
|
);
|
||||||
|
|
||||||
export default combineReducers<State, Actions>({
|
export function createRootReducer() {
|
||||||
application,
|
return combineReducers<State, Actions>({
|
||||||
connections: persistReducer<DevicesState, Actions>(
|
application,
|
||||||
{
|
connections: persistReducer<DevicesState, Actions>(
|
||||||
key: 'connections',
|
{
|
||||||
storage,
|
key: 'connections',
|
||||||
whitelist: [
|
storage,
|
||||||
'userPreferredDevice',
|
whitelist: [
|
||||||
'userPreferredPlugin',
|
'userPreferredDevice',
|
||||||
'userPreferredApp',
|
'userPreferredPlugin',
|
||||||
'enabledPlugins',
|
'userPreferredApp',
|
||||||
'enabledDevicePlugins',
|
'enabledPlugins',
|
||||||
],
|
'enabledDevicePlugins',
|
||||||
transforms: [
|
],
|
||||||
setTransformer({
|
transforms: [
|
||||||
whitelist: ['enabledDevicePlugins', 'userStarredDevicePlugins'],
|
setTransformer({
|
||||||
}),
|
whitelist: ['enabledDevicePlugins', 'userStarredDevicePlugins'],
|
||||||
],
|
}),
|
||||||
version: devicesPersistVersion,
|
],
|
||||||
migrate: createMigrate(devicesPersistMigrations),
|
version: devicesPersistVersion,
|
||||||
},
|
migrate: createMigrate(devicesPersistMigrations),
|
||||||
connections,
|
},
|
||||||
),
|
connections,
|
||||||
pluginStates,
|
),
|
||||||
pluginMessageQueue: pluginMessageQueue as any,
|
pluginStates,
|
||||||
notifications: persistReducer(
|
pluginMessageQueue: pluginMessageQueue as any,
|
||||||
{
|
notifications: persistReducer(
|
||||||
key: 'notifications',
|
{
|
||||||
storage,
|
key: 'notifications',
|
||||||
whitelist: ['blacklistedPlugins', 'blacklistedCategories'],
|
storage,
|
||||||
},
|
whitelist: ['blacklistedPlugins', 'blacklistedCategories'],
|
||||||
notifications,
|
},
|
||||||
),
|
notifications,
|
||||||
plugins: persistReducer<PluginsState, Actions>(
|
),
|
||||||
{
|
plugins: persistReducer<PluginsState, Actions>(
|
||||||
key: 'plugins',
|
{
|
||||||
storage,
|
key: 'plugins',
|
||||||
whitelist: ['marketplacePlugins', 'uninstalledPluginNames'],
|
storage,
|
||||||
transforms: [setTransformer({whitelist: ['uninstalledPluginNames']})],
|
whitelist: ['marketplacePlugins', 'uninstalledPluginNames'],
|
||||||
version: pluginsPersistVersion,
|
transforms: [setTransformer({whitelist: ['uninstalledPluginNames']})],
|
||||||
migrate: createMigrate(pluginsPersistMigrations),
|
version: pluginsPersistVersion,
|
||||||
},
|
migrate: createMigrate(pluginsPersistMigrations),
|
||||||
plugins,
|
},
|
||||||
),
|
plugins,
|
||||||
supportForm,
|
),
|
||||||
pluginManager,
|
supportForm,
|
||||||
user: persistReducer(
|
pluginManager,
|
||||||
{
|
user: persistReducer(
|
||||||
key: 'user',
|
{
|
||||||
storage,
|
key: 'user',
|
||||||
},
|
storage,
|
||||||
user,
|
},
|
||||||
),
|
user,
|
||||||
settingsState: persistReducer(
|
),
|
||||||
{key: 'settings', storage: settingsStorage},
|
settingsState: persistReducer(
|
||||||
settings,
|
{key: 'settings', storage: settingsStorage},
|
||||||
),
|
settings,
|
||||||
launcherSettingsState: persistReducer(
|
),
|
||||||
{
|
launcherSettingsState: persistReducer(
|
||||||
key: 'launcherSettings',
|
{
|
||||||
storage: launcherSettingsStorage,
|
key: 'launcherSettings',
|
||||||
serialize: false,
|
storage: launcherSettingsStorage,
|
||||||
// @ts-ignore: property is erroneously missing in redux-persist type definitions
|
serialize: false,
|
||||||
deserialize: false,
|
// @ts-ignore: property is erroneously missing in redux-persist type definitions
|
||||||
},
|
deserialize: false,
|
||||||
launcherSettings,
|
},
|
||||||
),
|
launcherSettings,
|
||||||
healthchecks: persistReducer<HealthcheckState, Actions>(
|
),
|
||||||
{
|
healthchecks: persistReducer<HealthcheckState, Actions>(
|
||||||
key: 'healthchecks',
|
{
|
||||||
storage,
|
key: 'healthchecks',
|
||||||
whitelist: ['acknowledgedProblems'],
|
storage,
|
||||||
},
|
whitelist: ['acknowledgedProblems'],
|
||||||
healthchecks,
|
},
|
||||||
),
|
healthchecks,
|
||||||
usageTracking,
|
),
|
||||||
pluginDownloads,
|
usageTracking,
|
||||||
pluginLists,
|
pluginDownloads,
|
||||||
});
|
pluginLists,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {Provider} from 'react-redux';
|
|||||||
import {createStore} from 'redux';
|
import {createStore} from 'redux';
|
||||||
import {LaunchEmulatorDialog} from '../LaunchEmulator';
|
import {LaunchEmulatorDialog} from '../LaunchEmulator';
|
||||||
|
|
||||||
import {rootReducer} from '../../../store';
|
import {createRootReducer} from '../../../reducers';
|
||||||
import {act} from 'react-dom/test-utils';
|
import {act} from 'react-dom/test-utils';
|
||||||
import {sleep} from '../../../utils';
|
import {sleep} from '../../../utils';
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ jest.mock('../../../devices/AndroidDevice', () => ({
|
|||||||
import {launchEmulator} from '../../../devices/AndroidDevice';
|
import {launchEmulator} from '../../../devices/AndroidDevice';
|
||||||
|
|
||||||
test('Can render and launch android apps', async () => {
|
test('Can render and launch android apps', async () => {
|
||||||
const store = createStore(rootReducer);
|
const store = createStore(createRootReducer());
|
||||||
const onClose = jest.fn();
|
const onClose = jest.fn();
|
||||||
|
|
||||||
const renderer = render(
|
const renderer = render(
|
||||||
|
|||||||
@@ -9,31 +9,43 @@
|
|||||||
|
|
||||||
import './global';
|
import './global';
|
||||||
import {createStore} from 'redux';
|
import {createStore} from 'redux';
|
||||||
import reducers, {Actions, State as StoreState, Store} from './reducers/index';
|
import {
|
||||||
|
createRootReducer,
|
||||||
|
Actions,
|
||||||
|
State as StoreState,
|
||||||
|
Store,
|
||||||
|
} from './reducers/index';
|
||||||
import {stateSanitizer} from './utils/reduxDevToolsConfig';
|
import {stateSanitizer} from './utils/reduxDevToolsConfig';
|
||||||
import isProduction from './utils/isProduction';
|
import isProduction from './utils/isProduction';
|
||||||
import {_SandyPluginDefinition} from 'flipper-plugin';
|
|
||||||
|
|
||||||
export const store: Store = createStore<StoreState, Actions, any, any>(
|
let store: Store;
|
||||||
rootReducer,
|
|
||||||
// @ts-ignore Type definition mismatch
|
|
||||||
window.__REDUX_DEVTOOLS_EXTENSION__
|
|
||||||
? window.__REDUX_DEVTOOLS_EXTENSION__({
|
|
||||||
// @ts-ignore: stateSanitizer is not part of type definition.
|
|
||||||
stateSanitizer,
|
|
||||||
})
|
|
||||||
: undefined,
|
|
||||||
);
|
|
||||||
|
|
||||||
export function rootReducer(
|
function initStore() {
|
||||||
state: StoreState | undefined,
|
const rootReducer = createRootReducer();
|
||||||
action: Actions,
|
|
||||||
): StoreState {
|
store = createStore<StoreState, Actions, any, any>(
|
||||||
return reducers(state, action);
|
rootReducer,
|
||||||
|
// @ts-ignore Type definition mismatch
|
||||||
|
window.__REDUX_DEVTOOLS_EXTENSION__
|
||||||
|
? window.__REDUX_DEVTOOLS_EXTENSION__({
|
||||||
|
// @ts-ignore: stateSanitizer is not part of type definition.
|
||||||
|
stateSanitizer,
|
||||||
|
})
|
||||||
|
: undefined,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!isProduction()) {
|
||||||
|
// For debugging purposes only
|
||||||
|
// @ts-ignore
|
||||||
|
window.flipperStore = store;
|
||||||
|
}
|
||||||
|
return store;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isProduction()) {
|
// grab store lazily, to not break module loading order...
|
||||||
// For debugging purposes only
|
export function getStore() {
|
||||||
// @ts-ignore
|
if (!store) {
|
||||||
window.flipperStore = store;
|
return initStore();
|
||||||
|
}
|
||||||
|
return store;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
import {createStore} from 'redux';
|
import {createStore} from 'redux';
|
||||||
import BaseDevice from '../devices/BaseDevice';
|
import BaseDevice from '../devices/BaseDevice';
|
||||||
import {rootReducer} from '../store';
|
import {createRootReducer} from '../reducers';
|
||||||
import {Store} from '../reducers/index';
|
import {Store} from '../reducers/index';
|
||||||
import Client, {ClientQuery, FlipperClientConnection} from '../Client';
|
import Client, {ClientQuery, FlipperClientConnection} from '../Client';
|
||||||
import {buildClientId} from '../utils/clientUtils';
|
import {buildClientId} from '../utils/clientUtils';
|
||||||
@@ -75,7 +75,7 @@ export default class MockFlipper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async init({plugins}: AppOptions = {}) {
|
public async init({plugins}: AppOptions = {}) {
|
||||||
this._store = createStore(rootReducer);
|
this._store = createStore(createRootReducer());
|
||||||
this._logger = getInstance();
|
this._logger = getInstance();
|
||||||
this.unsubscribePluginManager = pluginManager(this._store, this._logger, {
|
this.unsubscribePluginManager = pluginManager(this._store, this._logger, {
|
||||||
runSideEffectsSynchronously: true,
|
runSideEffectsSynchronously: true,
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
import {Store} from '../../reducers/index';
|
import {Store} from '../../reducers/index';
|
||||||
import {createStore} from 'redux';
|
import {createStore} from 'redux';
|
||||||
import {rootReducer} from '../../store';
|
import {createRootReducer} from '../../reducers';
|
||||||
import initialize, {getInfo} from '../info';
|
import initialize, {getInfo} from '../info';
|
||||||
import {registerLoadedPlugins} from '../../reducers/plugins';
|
import {registerLoadedPlugins} from '../../reducers/plugins';
|
||||||
import {TestUtils} from 'flipper-plugin';
|
import {TestUtils} from 'flipper-plugin';
|
||||||
@@ -37,7 +37,7 @@ describe('info', () => {
|
|||||||
let mockStore: Store;
|
let mockStore: Store;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockStore = createStore(rootReducer);
|
mockStore = createStore(createRootReducer());
|
||||||
mockStore.dispatch({type: 'INIT'});
|
mockStore.dispatch({type: 'INIT'});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {notification, Typography} from 'antd';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {ConsoleLogs} from '../chrome/ConsoleLogs';
|
import {ConsoleLogs} from '../chrome/ConsoleLogs';
|
||||||
import {setStaticView} from '../reducers/connections';
|
import {setStaticView} from '../reducers/connections';
|
||||||
import {store} from '../store';
|
import {getStore} from '../store';
|
||||||
import {Layout} from '../ui';
|
import {Layout} from '../ui';
|
||||||
import {v4 as uuid} from 'uuid';
|
import {v4 as uuid} from 'uuid';
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ export function showErrorNotification(message: string, description?: string) {
|
|||||||
See{' '}
|
See{' '}
|
||||||
<Link
|
<Link
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
store.dispatch(setStaticView(ConsoleLogs));
|
getStore().dispatch(setStaticView(ConsoleLogs));
|
||||||
notification.close(key);
|
notification.close(key);
|
||||||
}}>
|
}}>
|
||||||
logs
|
logs
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {render, fireEvent} from '@testing-library/react';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
// TODO T71355623
|
// TODO T71355623
|
||||||
// eslint-disable-next-line flipper/no-relative-imports-across-packages
|
// eslint-disable-next-line flipper/no-relative-imports-across-packages
|
||||||
import reducers, {Store} from '../../../../app/src/reducers';
|
import {Store, createRootReducer} from '../../../../app/src/reducers';
|
||||||
import configureStore from 'redux-mock-store';
|
import configureStore from 'redux-mock-store';
|
||||||
import {Provider} from 'react-redux';
|
import {Provider} from 'react-redux';
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ const values: Array<Value> = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const mockStore: Store = configureStore([])(
|
const mockStore: Store = configureStore([])(
|
||||||
reducers(undefined, {type: 'INIT'}),
|
createRootReducer()(undefined, {type: 'INIT'}),
|
||||||
) as Store;
|
) as Store;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
|||||||
@@ -86,7 +86,7 @@
|
|||||||
openError('Script failure. Check Chrome console for more info.');
|
openError('Script failure. Check Chrome console for more info.');
|
||||||
};
|
};
|
||||||
|
|
||||||
window.addEventListener('flipper-store-ready', () => global.Flipper.init());
|
window.addEventListener('flipper-store-ready', () => global.flipperInit());
|
||||||
|
|
||||||
document.body.appendChild(script);
|
document.body.appendChild(script);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
global.electronRequire = window.require;
|
global.electronRequire = window.require;
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
window.addEventListener('flipper-store-ready', () => global.Flipper.init());
|
window.addEventListener('flipper-store-ready', () => global.flipperInit());
|
||||||
</script>
|
</script>
|
||||||
<script src="bundle.js"></script>
|
<script src="bundle.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
Reference in New Issue
Block a user