Install pre-bundled packages 2/N

Summary: A first simple version of pre-bundled plugin installation. Currently both pre-bundled and source-only plugins are supported. Pre-bundled plugins should have folder "dist" inside and package.json's "main" field should point to the entry point script there.

Reviewed By: passy

Differential Revision: D19834020

fbshipit-source-id: 7e0b495fb9666acbb22fc32ca2382339cd9dc72f
This commit is contained in:
Anton Nikolaev
2020-02-12 04:55:55 -08:00
committed by Facebook Github Bot
parent c315691b2d
commit 707759f096
3 changed files with 29 additions and 23 deletions

View File

@@ -80,7 +80,7 @@ export default (store: Store, logger: Logger) => {
}; };
function getBundledPlugins(): Array<PluginDefinition> { function getBundledPlugins(): Array<PluginDefinition> {
if (!isProduction()) { if (!isProduction() || process.env.FLIPPER_NO_EMBEDDED_PLUGINS) {
// Plugins are only bundled in production builds // Plugins are only bundled in production builds
return []; return [];
} }

View File

@@ -38,7 +38,7 @@ function providePluginManagerNoDependencies(): PM {
return new PM({ignoredDependencies: [/.*/]}); return new PM({ignoredDependencies: [/.*/]});
} }
async function installPlugin(pluginDir: string) { async function installPluginFromTempDir(pluginDir: string) {
const packageJSONPath = path.join(pluginDir, 'package.json'); const packageJSONPath = path.join(pluginDir, 'package.json');
const packageJSON = JSON.parse( const packageJSON = JSON.parse(
(await fs.readFile(packageJSONPath)).toString(), (await fs.readFile(packageJSONPath)).toString(),
@@ -51,27 +51,25 @@ async function installPlugin(pluginDir: string) {
const destinationDir = path.join(PLUGIN_DIR, name); const destinationDir = path.join(PLUGIN_DIR, name);
// Clean up existing destination files. // Clean up existing destination files.
await fs.remove(destinationDir); await fs.remove(destinationDir);
await fs.ensureDir(destinationDir);
const pluginManager = providePluginManager(); const isPreBundled = await fs.pathExists(path.join(pluginDir, 'dist'));
// install the plugin dependencies into node_modules if (!isPreBundled) {
const nodeModulesDir = path.join(destinationDir, 'node_modules'); const pluginManager = providePluginManager();
pluginManager.options.pluginsPath = nodeModulesDir; // install the plugin dependencies into node_modules
const pluginInfo = await pluginManager.installFromPath(pluginDir); const nodeModulesDir = path.join(destinationDir, 'node_modules');
pluginManager.options.pluginsPath = nodeModulesDir;
const itselfDir = path.join(nodeModulesDir, name); await pluginManager.installFromPath(pluginDir);
// live-plugin-manager also installs plugin itself into the target dir, it's better remove it
await fs.remove(path.join(nodeModulesDir, name));
}
// copying plugin files into the destination folder // copying plugin files into the destination folder
const pluginFiles = await fs.readdir(itselfDir); const pluginFiles = await fs.readdir(pluginDir);
await Promise.all( await Promise.all(
pluginFiles.map(f => pluginFiles
fs.move(path.join(itselfDir, f), path.join(destinationDir, f)), .filter(f => f !== 'node_modules')
), .map(f => fs.move(path.join(pluginDir, f), path.join(destinationDir, f))),
); );
// live-plugin-manager also installs plugin itself into the target dir, it's better remove it
await fs.remove(itselfDir);
return pluginInfo;
} }
async function getPluginRootDir(dir: string) { async function getPluginRootDir(dir: string) {
@@ -99,8 +97,8 @@ export async function installPluginFromNpm(name: string) {
const plugManNoDep = providePluginManagerNoDependencies(); const plugManNoDep = providePluginManagerNoDependencies();
plugManNoDep.options.pluginsPath = tmpDir; plugManNoDep.options.pluginsPath = tmpDir;
await plugManNoDep.install(name); await plugManNoDep.install(name);
const pluginDir = path.join(tmpDir, name); const pluginTempDir = path.join(tmpDir, name);
return await installPlugin(pluginDir); await installPluginFromTempDir(pluginTempDir);
} finally { } finally {
if (await fs.pathExists(tmpDir)) { if (await fs.pathExists(tmpDir)) {
await fs.remove(tmpDir); await fs.remove(tmpDir);
@@ -118,7 +116,7 @@ export async function installPluginFromFile(packagePath: string) {
throw new Error('The package is not in tar.gz format or is empty'); throw new Error('The package is not in tar.gz format or is empty');
} }
const pluginDir = await getPluginRootDir(tmpDir); const pluginDir = await getPluginRootDir(tmpDir);
return await installPlugin(pluginDir); await installPluginFromTempDir(pluginDir);
} finally { } finally {
if (await fs.pathExists(tmpDir)) { if (await fs.pathExists(tmpDir)) {
await fs.remove(tmpDir); await fs.remove(tmpDir);

View File

@@ -210,9 +210,17 @@ async function compilePlugin(
pluginCache, pluginCache,
options, options,
) { ) {
const isPreBundled = fs.existsSync(path.join(rootDir, 'dist'));
const result = Object.assign({}, packageJSON, {rootDir, name, entry});
if (isPreBundled) {
// eslint-disable-next-line no-console
console.log(`🥫 Using pre-built version of ${name}...`);
result.out = path.resolve(rootDir, result.main);
return result;
}
const fileName = `${name}@${packageJSON.version || '0.0.0'}.js`; const fileName = `${name}@${packageJSON.version || '0.0.0'}.js`;
const out = path.join(pluginCache, fileName); const out = path.join(pluginCache, fileName);
const result = Object.assign({}, packageJSON, {rootDir, name, entry, out}); result.out = out;
// check if plugin needs to be compiled // check if plugin needs to be compiled
const rootDirCtime = await mostRecentlyChanged(rootDir); const rootDirCtime = await mostRecentlyChanged(rootDir);
if ( if (