Simplify bundled plugin setup

Summary: Stop bundling plugins into Flipper Server bundles. In later diffs, we will start building all plugins even in dev mode which removes the need to bundle them.

Reviewed By: lblasa

Differential Revision: D39276249

fbshipit-source-id: 091405cfcf58aa7e1bd2b382da40f8d9841ae6b1
This commit is contained in:
Andrey Goncharov
2022-09-15 10:02:19 -07:00
committed by Facebook GitHub Bot
parent a67a4e5d0f
commit a888e6affa
14 changed files with 24 additions and 129 deletions

View File

@@ -9,7 +9,6 @@
import {FlipperDoctor} from './doctor'; import {FlipperDoctor} from './doctor';
import { import {
BundledPluginDetails,
DeviceSpec, DeviceSpec,
DeviceType, DeviceType,
DownloadablePluginDetails, DownloadablePluginDetails,
@@ -254,7 +253,6 @@ export type FlipperServerCommands = {
'keychain-unset': (service: string) => Promise<void>; 'keychain-unset': (service: string) => Promise<void>;
'plugins-load-dynamic-plugins': () => Promise<InstalledPluginDetails[]>; 'plugins-load-dynamic-plugins': () => Promise<InstalledPluginDetails[]>;
'plugins-load-marketplace-plugins': () => Promise<MarketplacePluginDetails[]>; 'plugins-load-marketplace-plugins': () => Promise<MarketplacePluginDetails[]>;
'plugins-get-bundled-plugins': () => Promise<BundledPluginDetails[]>;
'plugins-get-installed-plugins': () => Promise<InstalledPluginDetails[]>; 'plugins-get-installed-plugins': () => Promise<InstalledPluginDetails[]>;
'plugins-get-updatable-plugins': ( 'plugins-get-updatable-plugins': (
query: string | undefined, query: string | undefined,

View File

@@ -75,12 +75,13 @@ export abstract class AbstractPluginInitializer {
protected async loadAllLocalVersions( protected async loadAllLocalVersions(
uninstalledPluginNames: Set<string>, uninstalledPluginNames: Set<string>,
): Promise<(BundledPluginDetails | InstalledPluginDetails)[]> { ): Promise<(BundledPluginDetails | InstalledPluginDetails)[]> {
const bundledPlugins = await getBundledPlugins(); this.bundledPlugins = Object.values(this.defaultPluginsIndex).map(
this.bundledPlugins = bundledPlugins; (defaultPluginEntry: any) => defaultPluginEntry.description,
);
const allLocalVersions = [ const allLocalVersions = [
...bundledPlugins,
...(await getDynamicPlugins()), ...(await getDynamicPlugins()),
...this.bundledPlugins,
].filter((p) => !uninstalledPluginNames.has(p.name)); ].filter((p) => !uninstalledPluginNames.has(p.name));
return allLocalVersions; return allLocalVersions;
@@ -147,24 +148,6 @@ export function getLatestCompatibleVersionOfEachPlugin<
return Array.from(latestCompatibleVersions.values()); return Array.from(latestCompatibleVersions.values());
} }
export async function getBundledPlugins(): Promise<
Array<BundledPluginDetails>
> {
if (getRenderHostInstance().serverConfig.env.NODE_ENV === 'test') {
return [];
}
try {
// defaultPlugins that are included in the Flipper distributive.
// List of default bundled plugins is written at build time to defaultPlugins/bundled.json.
return await getRenderHostInstance().flipperServer!.exec(
'plugins-get-bundled-plugins',
);
} catch (e) {
console.error('Failed to load list of bundled plugins', e);
return [];
}
}
export async function getDynamicPlugins(): Promise<InstalledPluginDetails[]> { export async function getDynamicPlugins(): Promise<InstalledPluginDetails[]> {
try { try {
return await getRenderHostInstance().flipperServer!.exec( return await getRenderHostInstance().flipperServer!.exec(

View File

@@ -30,9 +30,9 @@ export class HeadlessPluginInitializer extends AbstractPluginInitializer {
protected async requirePluginImpl( protected async requirePluginImpl(
pluginDetails: ActivatablePluginDetails, pluginDetails: ActivatablePluginDetails,
): Promise<_SandyPluginDefinition> { ): Promise<_SandyPluginDefinition> {
const plugin = pluginDetails.isBundled const plugin = await getRenderHostInstance().requirePlugin(
? this.defaultPluginsIndex[pluginDetails.name] (pluginDetails as InstalledPluginDetails).entry,
: await getRenderHostInstance().requirePlugin(pluginDetails.entry); );
if (!plugin) { if (!plugin) {
throw new Error( throw new Error(
`Failed to obtain plugin source for: ${pluginDetails.name}`, `Failed to obtain plugin source for: ${pluginDetails.name}`,

View File

@@ -46,7 +46,7 @@ export function initializeRenderHost(
restartFlipper() { restartFlipper() {
// TODO: // TODO:
}, },
loadDefaultPlugins: getDefaultPluginsIndex, loadDefaultPlugins: () => ({}),
serverConfig: flipperServerConfig, serverConfig: flipperServerConfig,
GK(gatekeeper) { GK(gatekeeper) {
return flipperServerConfig.gatekeepers[gatekeeper] ?? false; return flipperServerConfig.gatekeepers[gatekeeper] ?? false;
@@ -81,8 +81,3 @@ export function initializeRenderHost(
}, },
} as RenderHost; } as RenderHost;
} }
function getDefaultPluginsIndex() {
// TODO: Fix me
return {};
}

View File

@@ -435,7 +435,6 @@ export class FlipperServerImpl implements FlipperServer {
this.pluginManager.loadDynamicPlugins(), this.pluginManager.loadDynamicPlugins(),
'plugins-load-marketplace-plugins': () => 'plugins-load-marketplace-plugins': () =>
this.pluginManager.loadMarketplacePlugins(), this.pluginManager.loadMarketplacePlugins(),
'plugins-get-bundled-plugins': () => this.pluginManager.getBundledPlugins(),
'plugins-get-installed-plugins': () => 'plugins-get-installed-plugins': () =>
this.pluginManager.getInstalledPlugins(), this.pluginManager.getInstalledPlugins(),
'plugins-remove-plugins': (plugins) => 'plugins-remove-plugins': (plugins) =>

View File

@@ -13,7 +13,6 @@ import tmp from 'tmp';
import {promisify} from 'util'; import {promisify} from 'util';
import {default as axios} from 'axios'; import {default as axios} from 'axios';
import { import {
BundledPluginDetails,
DownloadablePluginDetails, DownloadablePluginDetails,
ExecuteMessage, ExecuteMessage,
FlipperServerForServerAddOn, FlipperServerForServerAddOn,
@@ -77,28 +76,6 @@ export class PluginManager {
return await fs.readFile(path, 'utf8'); return await fs.readFile(path, 'utf8');
} }
async getBundledPlugins(): Promise<Array<BundledPluginDetails>> {
if (
process.env.NODE_ENV === 'test' ||
process.env.FLIPPER_NO_BUNDLED_PLUGINS === 'true'
) {
return [];
}
// defaultPlugins that are included in the Flipper distributive.
// List of default bundled plugins is written at build time to defaultPlugins/bundled.json.
const pluginPath = getStaticPath(
path.join('defaultPlugins', 'bundled.json'),
{asarUnpacked: true},
);
let bundledPlugins: Array<BundledPluginDetails> = [];
try {
bundledPlugins = await fs.readJson(pluginPath);
} catch (e) {
console.error('Failed to load list of bundled plugins', e);
}
return bundledPlugins;
}
async loadMarketplacePlugins() { async loadMarketplacePlugins() {
console.info('Load available plugins from marketplace'); console.info('Load available plugins from marketplace');
return loadMarketplacePlugins(this.flipperServer, ''); return loadMarketplacePlugins(this.flipperServer, '');

View File

@@ -19,7 +19,6 @@ import {InstalledPluginDetails} from 'flipper-common';
import {getStaticPath} from '../utils/pathUtils'; import {getStaticPath} from '../utils/pathUtils';
// Load "dynamic" plugins, e.g. those which are either pre-installed (default), installed or loaded from sources (for development). // Load "dynamic" plugins, e.g. those which are either pre-installed (default), installed or loaded from sources (for development).
// This opposed to "bundled" plugins which are included into Flipper bundle.
export async function loadDynamicPlugins(): Promise<InstalledPluginDetails[]> { export async function loadDynamicPlugins(): Promise<InstalledPluginDetails[]> {
if (process.env.NODE_ENV === 'test') { if (process.env.NODE_ENV === 'test') {
return []; return [];
@@ -36,29 +35,14 @@ export async function loadDynamicPlugins(): Promise<InstalledPluginDetails[]> {
ex, ex,
), ),
); );
const bundledPlugins = new Set<string>(
( const [installedPlugins, sourcePlugins] = await Promise.all([
await fs.readJson(
getStaticPath(path.join('defaultPlugins', 'bundled.json'), {
asarUnpacked: true,
}),
)
).map((p: any) => p.name) as string[],
);
console.log(
`✅ Detected ${bundledPlugins.size} bundled plugins: ${Array.from(
bundledPlugins,
).join(', ')}.`,
);
const [installedPlugins, unfilteredSourcePlugins] = await Promise.all([
process.env.FLIPPER_NO_PLUGIN_MARKETPLACE process.env.FLIPPER_NO_PLUGIN_MARKETPLACE
? Promise.resolve([]) ? Promise.resolve([])
: getAllInstalledPluginVersions(), : getAllInstalledPluginVersions(),
getSourcePlugins(), getSourcePlugins(),
]); ]);
const sourcePlugins = unfilteredSourcePlugins.filter(
(p) => !bundledPlugins.has(p.name),
);
const defaultPluginsDir = getStaticPath('defaultPlugins', { const defaultPluginsDir = getStaticPath('defaultPlugins', {
asarUnpacked: true, asarUnpacked: true,
}); });

View File

@@ -20,15 +20,6 @@ declare global {
} }
global.FlipperPlugin = FlipperPluginSDK; global.FlipperPlugin = FlipperPluginSDK;
// defaultPlugins has to be required after we set FlipperPlugin.
// In server add-ons, developers might import utilities from 'flipper-plugin'
// In babel-transformer/plugin-flipper-requires flipper-plugin is replaces with global.FlipperPlugin.
// If defaultPlugins is required before we set global.FlipperPlugin,
// then flipper-plugin replaced with global.FlipperPlugin is evaluated in server add-ons before we set it - to undefined.
//
// The file is generated automatically by "prepareDefaultPlugins" in "scripts"
const defaultPlugins = require('../defaultPlugins').default;
interface ServerAddOnModule { interface ServerAddOnModule {
default: ServerAddOnFn<any, any>; default: ServerAddOnFn<any, any>;
} }
@@ -39,18 +30,9 @@ export const loadServerAddOn = (
): ServerAddOnModule => { ): ServerAddOnModule => {
console.debug('loadPlugin', pluginName, details); console.debug('loadPlugin', pluginName, details);
if (details.isBundled) {
const bundledPlugin = defaultPlugins[pluginName];
assertNotNull(
bundledPlugin,
`loadPlugin (isBundled = true) -> plugin ${pluginName} not found.`,
);
return bundledPlugin;
}
assertNotNull( assertNotNull(
details.path, details.path,
`loadPlugin (isBundled = false) -> server add-on path is empty plugin ${pluginName}.`, `loadPlugin -> server add-on path is empty plugin ${pluginName}.`,
); );
// eslint-disable-next-line no-eval // eslint-disable-next-line no-eval

View File

@@ -127,7 +127,7 @@ export const requirePluginInternal = async (
pluginDetails: ActivatablePluginDetails, pluginDetails: ActivatablePluginDetails,
): Promise<PluginDefinition> => { ): Promise<PluginDefinition> => {
let plugin = pluginDetails.isBundled let plugin = pluginDetails.isBundled
? defaultPluginsIndex[pluginDetails.name] ? defaultPluginsIndex[pluginDetails.name].source
: await getRenderHostInstance().requirePlugin(pluginDetails.entry); : await getRenderHostInstance().requirePlugin(pluginDetails.entry);
if (!plugin) { if (!plugin) {
throw new Error( throw new Error(

View File

@@ -353,7 +353,7 @@ async function buildServerRelease() {
// create plugin output dir // create plugin output dir
await fs.mkdirp(path.join(dir, 'static', 'defaultPlugins')); await fs.mkdirp(path.join(dir, 'static', 'defaultPlugins'));
await prepareDefaultPlugins(argv.channel === 'insiders', true); await prepareDefaultPlugins(argv.channel === 'insiders');
await buildServerAddOns(false); await buildServerAddOns(false);
await buildHeadlessPlugins(false); await buildHeadlessPlugins(false);
await compileServerMain(false); await compileServerMain(false);

View File

@@ -27,6 +27,8 @@ import {
genMercurialRevision, genMercurialRevision,
prepareDefaultPlugins, prepareDefaultPlugins,
moveSourceMaps, moveSourceMaps,
buildServerAddOns,
buildHeadlessPlugins,
} from './build-utils'; } from './build-utils';
import isFB from './isFB'; import isFB from './isFB';
import copyPackageWithDependencies from './copy-package-with-dependencies'; import copyPackageWithDependencies from './copy-package-with-dependencies';
@@ -311,6 +313,8 @@ async function copyStaticFolder(buildFolder: string) {
await compileMain(); await compileMain();
await prepareDefaultPlugins(argv.channel === 'insiders'); await prepareDefaultPlugins(argv.channel === 'insiders');
await buildServerAddOns(false);
await buildHeadlessPlugins(false);
await copyStaticFolder(dir); await copyStaticFolder(dir);
await downloadIcons(dir); await downloadIcons(dir);
await compileRenderer(dir); await compileRenderer(dir);

View File

@@ -36,7 +36,6 @@ import {
serverDir, serverDir,
rootDir, rootDir,
browserUiDir, browserUiDir,
serverCoreDir,
} from './paths'; } from './paths';
import pFilter from 'p-filter'; import pFilter from 'p-filter';
import child from 'child_process'; import child from 'child_process';
@@ -44,7 +43,6 @@ import pMap from 'p-map';
// eslint-disable-next-line flipper/no-relative-imports-across-packages // eslint-disable-next-line flipper/no-relative-imports-across-packages
const {version} = require('../package.json'); const {version} = require('../package.json');
const dev = process.env.NODE_ENV !== 'production'; const dev = process.env.NODE_ENV !== 'production';
// For insiders builds we bundle top 5 popular device plugins, // For insiders builds we bundle top 5 popular device plugins,
@@ -75,10 +73,7 @@ export function die(err: Error) {
process.exit(1); process.exit(1);
} }
export async function prepareDefaultPlugins( export async function prepareDefaultPlugins(isInsidersBuild: boolean = false) {
isInsidersBuild: boolean = false,
flipperServerBuild = false,
) {
console.log( console.log(
`⚙️ Preparing default plugins (isInsidersBuild=${isInsidersBuild})...`, `⚙️ Preparing default plugins (isInsidersBuild=${isInsidersBuild})...`,
); );
@@ -107,10 +102,7 @@ export async function prepareDefaultPlugins(
await buildDefaultPlugins(defaultPlugins); await buildDefaultPlugins(defaultPlugins);
await generateDefaultPluginEntryPoints([]); // calling it here just to generate empty indexes await generateDefaultPluginEntryPoints([]); // calling it here just to generate empty indexes
} else { } else {
await generateDefaultPluginEntryPoints( await generateDefaultPluginEntryPoints(defaultPlugins);
defaultPlugins,
flipperServerBuild,
);
} }
} }
console.log('✅ Prepared default plugins.'); console.log('✅ Prepared default plugins.');
@@ -155,7 +147,6 @@ function getGeneratedIndex(pluginRequires: string) {
async function generateDefaultPluginEntryPoints( async function generateDefaultPluginEntryPoints(
defaultPlugins: InstalledPluginDetails[], defaultPlugins: InstalledPluginDetails[],
flipperServerBuild?: boolean,
) { ) {
console.log( console.log(
`⚙️ Generating entry points for ${defaultPlugins.length} bundled plugins...`, `⚙️ Generating entry points for ${defaultPlugins.length} bundled plugins...`,
@@ -173,10 +164,7 @@ async function generateDefaultPluginEntryPoints(
serverAddOnEntry: undefined, serverAddOnEntry: undefined,
} as BundledPluginDetails), } as BundledPluginDetails),
); );
await fs.writeJSON(
path.join(defaultPluginsDir, 'bundled.json'),
bundledPlugins,
);
const pluginRequires = bundledPlugins const pluginRequires = bundledPlugins
.map( .map(
(x) => (x) =>
@@ -195,22 +183,6 @@ async function generateDefaultPluginEntryPoints(
generatedIndex, generatedIndex,
); );
const serverAddOns = flipperServerBuild
? []
: defaultPlugins.filter(({serverAddOnSource}) => !!serverAddOnSource);
const serverAddOnRequires = serverAddOns
.map(
(x) =>
` '${x.name}': tryRequire('${x.name}', () => require('${x.name}/${x.serverAddOnSource}'))`,
)
.join(',\n');
const generatedIndexServerAddOns = getGeneratedIndex(serverAddOnRequires);
await fs.ensureDir(path.join(serverCoreDir, 'src', 'defaultPlugins'));
await fs.writeFile(
path.join(serverCoreDir, 'src', 'defaultPlugins', 'index.tsx'),
generatedIndexServerAddOns,
);
console.log('✅ Generated bundled plugin entry points.'); console.log('✅ Generated bundled plugin entry points.');
} }

View File

@@ -24,6 +24,7 @@ import {
compileMain, compileMain,
prepareDefaultPlugins, prepareDefaultPlugins,
buildHeadlessPlugins, buildHeadlessPlugins,
buildServerAddOns,
} from './build-utils'; } from './build-utils';
import Watchman from './watchman'; import Watchman from './watchman';
// @ts-ignore no typings for metro // @ts-ignore no typings for metro
@@ -445,6 +446,7 @@ function checkDevServer() {
await prepareDefaultPlugins( await prepareDefaultPlugins(
process.env.FLIPPER_RELEASE_CHANNEL === 'insiders', process.env.FLIPPER_RELEASE_CHANNEL === 'insiders',
); );
await buildServerAddOns(true);
await buildHeadlessPlugins(true); await buildHeadlessPlugins(true);
await ensurePluginFoldersWatchable(); await ensurePluginFoldersWatchable();
const port = await detect(DEFAULT_PORT); const port = await detect(DEFAULT_PORT);

View File

@@ -186,10 +186,9 @@ async function startWatchChanges() {
} }
await prepareDefaultPlugins( await prepareDefaultPlugins(
process.env.FLIPPER_RELEASE_CHANNEL === 'insiders', process.env.FLIPPER_RELEASE_CHANNEL === 'insiders',
true,
); );
await buildHeadlessPlugins(true);
await buildServerAddOns(true); await buildServerAddOns(true);
await buildHeadlessPlugins(true);
await ensurePluginFoldersWatchable(); await ensurePluginFoldersWatchable();
// builds and starts // builds and starts