Unload uninstalled plugins from Electron cache
Summary: Electron/Node.js does not garbage collects unloaded modules by default. Need to cleanup require.cache to fully unload them. Reviewed By: passy Differential Revision: D25545962 fbshipit-source-id: 4dce32f39e22adcd2b4f5a55853551379e786e7b
This commit is contained in:
committed by
Facebook GitHub Bot
parent
965559ee65
commit
756edf9860
@@ -28,6 +28,7 @@ import {_SandyPluginDefinition} from 'flipper-plugin';
|
|||||||
import BaseDevice from './devices/BaseDevice';
|
import BaseDevice from './devices/BaseDevice';
|
||||||
import {State as PluginStates} from './reducers/pluginStates';
|
import {State as PluginStates} from './reducers/pluginStates';
|
||||||
import {ActivatablePluginDetails} from 'flipper-plugin-lib';
|
import {ActivatablePluginDetails} from 'flipper-plugin-lib';
|
||||||
|
import {unloadModule} from './utils/electronModuleCache';
|
||||||
|
|
||||||
export const store: Store = createStore<StoreState, Actions, any, any>(
|
export const store: Store = createStore<StoreState, Actions, any, any>(
|
||||||
rootReducer,
|
rootReducer,
|
||||||
@@ -168,6 +169,11 @@ function updateClientPlugin(
|
|||||||
];
|
];
|
||||||
});
|
});
|
||||||
cleanupPluginStates(draft.pluginStates, plugin.id);
|
cleanupPluginStates(draft.pluginStates, plugin.id);
|
||||||
|
const previousVersion = draft.plugins.clientPlugins.get(plugin.id);
|
||||||
|
if (previousVersion) {
|
||||||
|
// unload previous version from Electron cache
|
||||||
|
unloadPluginModule(previousVersion.details);
|
||||||
|
}
|
||||||
// update plugin definition
|
// update plugin definition
|
||||||
draft.plugins.clientPlugins.set(plugin.id, plugin);
|
draft.plugins.clientPlugins.set(plugin.id, plugin);
|
||||||
// start plugin for each client
|
// start plugin for each client
|
||||||
@@ -191,6 +197,7 @@ function uninstallPlugin(state: StoreState, plugin: PluginDefinition) {
|
|||||||
delete draft.pluginMessageQueue[pluginKey];
|
delete draft.pluginMessageQueue[pluginKey];
|
||||||
});
|
});
|
||||||
cleanupPluginStates(draft.pluginStates, plugin.id);
|
cleanupPluginStates(draft.pluginStates, plugin.id);
|
||||||
|
unloadPluginModule(plugin.details);
|
||||||
draft.plugins.clientPlugins.delete(plugin.id);
|
draft.plugins.clientPlugins.delete(plugin.id);
|
||||||
draft.plugins.devicePlugins.delete(plugin.id);
|
draft.plugins.devicePlugins.delete(plugin.id);
|
||||||
draft.pluginManager.uninstalledPlugins.add(plugin.details.name);
|
draft.pluginManager.uninstalledPlugins.add(plugin.details.name);
|
||||||
@@ -207,6 +214,11 @@ function updateDevicePlugin(state: StoreState, plugin: DevicePluginDefinition) {
|
|||||||
d.unloadDevicePlugin(plugin.id);
|
d.unloadDevicePlugin(plugin.id);
|
||||||
});
|
});
|
||||||
cleanupPluginStates(draft.pluginStates, plugin.id);
|
cleanupPluginStates(draft.pluginStates, plugin.id);
|
||||||
|
const previousVersion = draft.plugins.devicePlugins.get(plugin.id);
|
||||||
|
if (previousVersion) {
|
||||||
|
// unload previous version from Electron cache
|
||||||
|
unloadPluginModule(previousVersion.details);
|
||||||
|
}
|
||||||
draft.plugins.devicePlugins.set(plugin.id, plugin);
|
draft.plugins.devicePlugins.set(plugin.id, plugin);
|
||||||
devicesWithEnabledPlugin.forEach((d) => {
|
devicesWithEnabledPlugin.forEach((d) => {
|
||||||
d.loadDevicePlugin(plugin);
|
d.loadDevicePlugin(plugin);
|
||||||
@@ -245,3 +257,11 @@ function cleanupPluginStates(pluginStates: PluginStates, pluginId: string) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function unloadPluginModule(plugin: ActivatablePluginDetails) {
|
||||||
|
if (plugin.isBundled) {
|
||||||
|
// We cannot unload bundled plugin.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
unloadModule(plugin.entry);
|
||||||
|
}
|
||||||
|
|||||||
16
desktop/app/src/utils/electronModuleCache.tsx
Normal file
16
desktop/app/src/utils/electronModuleCache.tsx
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*
|
||||||
|
* @format
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function unloadModule(path: string) {
|
||||||
|
const resolvedPath = global.electronRequire.resolve(path);
|
||||||
|
if (!resolvedPath || !global.electronRequire.cache[resolvedPath]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
delete global.electronRequire.cache[resolvedPath];
|
||||||
|
}
|
||||||
6
desktop/types/nodejs.d.ts
vendored
6
desktop/types/nodejs.d.ts
vendored
@@ -11,7 +11,11 @@ declare module NodeJS {
|
|||||||
interface Global {
|
interface Global {
|
||||||
__REVISION__: string | undefined;
|
__REVISION__: string | undefined;
|
||||||
__VERSION__: string;
|
__VERSION__: string;
|
||||||
electronRequire: (name: string) => any;
|
electronRequire: {
|
||||||
|
(name: string): any;
|
||||||
|
resolve: (module: string) => string;
|
||||||
|
cache: {[module: string]: any};
|
||||||
|
};
|
||||||
window: Window | undefined;
|
window: Window | undefined;
|
||||||
WebSocket: any;
|
WebSocket: any;
|
||||||
fetch: any;
|
fetch: any;
|
||||||
|
|||||||
Reference in New Issue
Block a user