diff --git a/src/chrome/PluginInstaller.tsx b/src/chrome/PluginInstaller.tsx index 022a4fa9a..e995a1db8 100644 --- a/src/chrome/PluginInstaller.tsx +++ b/src/chrome/PluginInstaller.tsx @@ -30,7 +30,6 @@ import {List} from 'immutable'; import algoliasearch from 'algoliasearch'; import path from 'path'; import fs from 'fs-extra'; -import {PluginManager as PM} from 'live-plugin-manager'; import {reportPlatformFailures, reportUsage} from '../utils/metrics'; import restartFlipper from '../utils/restartFlipper'; import { @@ -38,17 +37,17 @@ import { PluginDefinition, registerInstalledPlugins, } from '../reducers/pluginManager'; -import {PLUGIN_DIR, readInstalledPlugins} from '../dispatcher/pluginManager'; -import {State as AppState, Store} from '../reducers'; +import { + PLUGIN_DIR, + readInstalledPlugins, + providePluginManager, + provideSearchIndex, +} from '../utils/pluginManager'; +import {State as AppState} from '../reducers'; import {connect} from 'react-redux'; import {Dispatch, Action} from 'redux'; -const ALGOLIA_APPLICATION_ID = 'OFCNCOG2CU'; -const ALGOLIA_API_KEY = 'f54e21fa3a2a0160595bb058179bfb1e'; const TAG = 'PluginInstaller'; -const PluginManager = new PM({ - ignoredDependencies: ['flipper', 'react', 'react-dom', '@types/*'], -}); const EllipsisText = styled(Text)({ overflow: 'hidden', @@ -111,10 +110,7 @@ type OwnProps = { type Props = OwnProps & PropsFromState & DispatchFromProps; const defaultProps: OwnProps = { - searchIndexFactory: () => { - const client = algoliasearch(ALGOLIA_APPLICATION_ID, ALGOLIA_API_KEY); - return client.initIndex('npm-search'); - }, + searchIndexFactory: provideSearchIndex, autoHeight: false, }; @@ -208,13 +204,14 @@ function InstallButton(props: { // create empty watchman config (required by metro's file watcher) await fs.writeFile(path.join(PLUGIN_DIR, '.watchmanconfig'), '{}'); + const pluginManager = providePluginManager(); // install the plugin and all it's dependencies into node_modules - PluginManager.options.pluginsPath = path.join( + pluginManager.options.pluginsPath = path.join( PLUGIN_DIR, props.name, 'node_modules', ); - await PluginManager.install(props.name); + await pluginManager.install(props.name); // move the plugin itself out of the node_modules folder const pluginDir = path.join( diff --git a/src/dispatcher/pluginManager.tsx b/src/dispatcher/pluginManager.tsx index e3265b594..18b904520 100644 --- a/src/dispatcher/pluginManager.tsx +++ b/src/dispatcher/pluginManager.tsx @@ -9,46 +9,8 @@ import {Store} from '../reducers/index'; import {Logger} from '../fb-interfaces/Logger'; -import path from 'path'; -import fs from 'fs-extra'; -import {homedir} from 'os'; -import { - registerInstalledPlugins, - PluginMap, - PluginDefinition, -} from '../reducers/pluginManager'; - -export const PLUGIN_DIR = path.join(homedir(), '.flipper', 'thirdparty'); - -export async function readInstalledPlugins(): Promise { - const pluginDirExists = await fs.pathExists(PLUGIN_DIR); - - if (!pluginDirExists) { - return new Map(); - } - const dirs = await fs.readdir(PLUGIN_DIR); - const plugins = await Promise.all<[string, PluginDefinition]>( - dirs.map( - name => - new Promise(async (resolve, reject) => { - if (!(await fs.lstat(path.join(PLUGIN_DIR, name))).isDirectory()) { - return resolve(undefined); - } - - const packageJSON = await fs.readFile( - path.join(PLUGIN_DIR, name, 'package.json'), - ); - - try { - resolve([name, JSON.parse(packageJSON.toString())]); - } catch (e) { - reject(e); - } - }), - ), - ); - return new Map(plugins.filter(Boolean)); -} +import {registerInstalledPlugins} from '../reducers/pluginManager'; +import {readInstalledPlugins} from '../utils/pluginManager'; function refreshInstalledPlugins(store: Store) { readInstalledPlugins().then(plugins => diff --git a/src/utils/pluginManager.tsx b/src/utils/pluginManager.tsx new file mode 100644 index 000000000..2f08aef5c --- /dev/null +++ b/src/utils/pluginManager.tsx @@ -0,0 +1,63 @@ +/** + * 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 + */ + +import path from 'path'; +import fs from 'fs-extra'; +import {homedir} from 'os'; +import {PluginMap, PluginDefinition} from '../reducers/pluginManager'; +import {PluginManager as PM} from 'live-plugin-manager'; +import algoliasearch from 'algoliasearch'; + +const ALGOLIA_APPLICATION_ID = 'OFCNCOG2CU'; +const ALGOLIA_API_KEY = 'f54e21fa3a2a0160595bb058179bfb1e'; + +// TODO(T57014856): The use should be constrained to just this module when the +// refactor is done. +export function providePluginManager(): PM { + return new PM({ + ignoredDependencies: ['flipper', 'react', 'react-dom', '@types/*'], + }); +} + +// TODO(T57014856): This should be private, too. +export function provideSearchIndex(): algoliasearch.Index { + const client = algoliasearch(ALGOLIA_APPLICATION_ID, ALGOLIA_API_KEY); + return client.initIndex('npm-search'); +} + +export const PLUGIN_DIR = path.join(homedir(), '.flipper', 'thirdparty'); +export async function readInstalledPlugins(): Promise { + const pluginDirExists = await fs.pathExists(PLUGIN_DIR); + + if (!pluginDirExists) { + return new Map(); + } + const dirs = await fs.readdir(PLUGIN_DIR); + const plugins = await Promise.all<[string, PluginDefinition]>( + dirs.map( + name => + new Promise(async (resolve, reject) => { + if (!(await fs.lstat(path.join(PLUGIN_DIR, name))).isDirectory()) { + return resolve(undefined); + } + + const packageJSON = await fs.readFile( + path.join(PLUGIN_DIR, name, 'package.json'), + ); + + try { + resolve([name, JSON.parse(packageJSON.toString())]); + } catch (e) { + reject(e); + } + }), + ), + ); + return new Map(plugins.filter(Boolean)); +}