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 {State as PluginStates} from './reducers/pluginStates';
|
||||
import {ActivatablePluginDetails} from 'flipper-plugin-lib';
|
||||
import {unloadModule} from './utils/electronModuleCache';
|
||||
|
||||
export const store: Store = createStore<StoreState, Actions, any, any>(
|
||||
rootReducer,
|
||||
@@ -168,6 +169,11 @@ function updateClientPlugin(
|
||||
];
|
||||
});
|
||||
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
|
||||
draft.plugins.clientPlugins.set(plugin.id, plugin);
|
||||
// start plugin for each client
|
||||
@@ -191,6 +197,7 @@ function uninstallPlugin(state: StoreState, plugin: PluginDefinition) {
|
||||
delete draft.pluginMessageQueue[pluginKey];
|
||||
});
|
||||
cleanupPluginStates(draft.pluginStates, plugin.id);
|
||||
unloadPluginModule(plugin.details);
|
||||
draft.plugins.clientPlugins.delete(plugin.id);
|
||||
draft.plugins.devicePlugins.delete(plugin.id);
|
||||
draft.pluginManager.uninstalledPlugins.add(plugin.details.name);
|
||||
@@ -207,6 +214,11 @@ function updateDevicePlugin(state: StoreState, plugin: DevicePluginDefinition) {
|
||||
d.unloadDevicePlugin(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);
|
||||
devicesWithEnabledPlugin.forEach((d) => {
|
||||
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 {
|
||||
__REVISION__: string | undefined;
|
||||
__VERSION__: string;
|
||||
electronRequire: (name: string) => any;
|
||||
electronRequire: {
|
||||
(name: string): any;
|
||||
resolve: (module: string) => string;
|
||||
cache: {[module: string]: any};
|
||||
};
|
||||
window: Window | undefined;
|
||||
WebSocket: any;
|
||||
fetch: any;
|
||||
|
||||
Reference in New Issue
Block a user