Ignore persistToLocalStorage in headless mode

Summary:
In a headless mode we do not have access to local storage. As a result, headless plugins that try to use `persistToLocalStorage` option crash. We should ignore the option for these plugins for now and add a way to persist the plugin state to the disk in a headless mode in the future.

CHANGELOG: Ignore persistToLocalStorage in headless mode

Resolves https://github.com/facebook/flipper/issues/4190

Reviewed By: lblasa

Differential Revision: D40341873

fbshipit-source-id: 40774c0024f79cf1652f24146fd16f6a101ca99e
This commit is contained in:
Andrey Goncharov
2022-10-14 02:26:43 -07:00
committed by Facebook GitHub Bot
parent 7d5cfc82ea
commit 27fd60b659
4 changed files with 23 additions and 3 deletions

View File

@@ -54,6 +54,8 @@ export {createDataSource} from './state/createDataSource';
export { export {
createState, createState,
_setAtomPersistentStorage,
AtomPersistentStorage,
Atom, Atom,
isAtom, isAtom,
ReadOnlyAtom as _ReadOnlyAtom, ReadOnlyAtom as _ReadOnlyAtom,

View File

@@ -106,7 +106,7 @@ export function createState(
options: StateOptions = {}, options: StateOptions = {},
): Atom<any> { ): Atom<any> {
const atom = new AtomValue(initialValue); const atom = new AtomValue(initialValue);
if (options?.persistToLocalStorage) { if (options?.persistToLocalStorage && atomStorage) {
syncAtomWithLocalStorage(options, atom); syncAtomWithLocalStorage(options, atom);
} else { } else {
registerStorageAtom(options.persist, atom); registerStorageAtom(options.persist, atom);
@@ -114,12 +114,26 @@ export function createState(
return atom; return atom;
} }
export interface AtomPersistentStorage {
getItem(key: string): string | null;
setItem(key: string, value: string): void;
}
let atomStorage: AtomPersistentStorage | undefined;
export function _setAtomPersistentStorage(newStorage: AtomPersistentStorage) {
atomStorage = newStorage;
}
function syncAtomWithLocalStorage(options: StateOptions, atom: AtomValue<any>) { function syncAtomWithLocalStorage(options: StateOptions, atom: AtomValue<any>) {
if (!options?.persist) { if (!options?.persist) {
throw new Error( throw new Error(
"The 'persist' option should be set when 'persistToLocalStorage' is set", "The 'persist' option should be set when 'persistToLocalStorage' is set",
); );
} }
if (!atomStorage) {
throw new Error(
"'atomStorage' is not implemented. Use 'setAtomPersistentStorage' to set AtomPersistentStorage implementation",
);
}
const pluginInstance = getCurrentPluginInstance(); const pluginInstance = getCurrentPluginInstance();
if (!pluginInstance) { if (!pluginInstance) {
throw new Error( throw new Error(
@@ -127,12 +141,12 @@ function syncAtomWithLocalStorage(options: StateOptions, atom: AtomValue<any>) {
); );
} }
const storageKey = `flipper:${pluginInstance.definition.id}:atom:${options.persist}`; const storageKey = `flipper:${pluginInstance.definition.id}:atom:${options.persist}`;
const storedValue = window.localStorage.getItem(storageKey); const storedValue = atomStorage.getItem(storageKey);
if (storedValue != null) { if (storedValue != null) {
atom.deserialize(JSON.parse(storedValue)); atom.deserialize(JSON.parse(storedValue));
} }
atom.subscribe(() => { atom.subscribe(() => {
window.localStorage.setItem(storageKey, JSON.stringify(atom.serialize())); atomStorage!.setItem(storageKey, JSON.stringify(atom.serialize()));
}); });
} }

View File

@@ -81,6 +81,7 @@ test('Correct top level API exposed', () => {
expect(exposedTypes.sort()).toMatchInlineSnapshot(` expect(exposedTypes.sort()).toMatchInlineSnapshot(`
Array [ Array [
"Atom", "Atom",
"AtomPersistentStorage",
"CrashLog", "CrashLog",
"CrashLogListener", "CrashLogListener",
"CreatePasteArgs", "CreatePasteArgs",

View File

@@ -7,6 +7,9 @@
* @format * @format
*/ */
import {_setAtomPersistentStorage} from 'flipper-plugin-core';
_setAtomPersistentStorage(window.localStorage);
export * from 'flipper-plugin-core'; export * from 'flipper-plugin-core';
import styledImport from '@emotion/styled'; import styledImport from '@emotion/styled';