Re-use pkg-lib for runtime plugin compilation

Summary: Re-use the same function for plugin building both at publishing time by "flipper-pkg" and in runtime by Flipper itself.

Reviewed By: jknoxville

Differential Revision: D21129685

fbshipit-source-id: b7bff6737310352d28a14223128f127ac4d2eebf
This commit is contained in:
Anton Nikolaev
2020-04-20 06:57:48 -07:00
committed by Facebook GitHub Bot
parent ca2d04a5da
commit 8a7470556e
7 changed files with 93 additions and 83 deletions

View File

@@ -9,20 +9,16 @@
import path from 'path';
import fs from 'fs-extra';
import Metro from 'metro';
import util from 'util';
import recursiveReaddir from 'recursive-readdir';
import pMap from 'p-map';
import {homedir} from 'os';
import {getWatchFolders, PluginDetails} from 'flipper-pkg-lib';
import {runBuild, PluginDetails} from 'flipper-pkg-lib';
import getPlugins from './getPlugins';
import startWatchPlugins from './startWatchPlugins';
const HOME_DIR = homedir();
let metroDir: string | undefined;
const metroDirPromise = getMetroDir().then((dir) => (metroDir = dir));
const DEFAULT_COMPILE_OPTIONS: CompileOptions = {
force: false,
failSilently: true,
@@ -97,57 +93,18 @@ async function startWatchChanges(
),
);
}
function hash(string: string) {
let hash = 0;
if (string.length === 0) {
return hash;
}
let chr;
for (let i = 0; i < string.length; i++) {
chr = string.charCodeAt(i);
hash = (hash << 5) - hash + chr;
hash |= 0;
}
return hash;
}
const fileToIdMap = new Map();
const createModuleIdFactory = () => (filePath: string) => {
if (filePath === '__prelude__') {
return 0;
}
let id = fileToIdMap.get(filePath);
if (typeof id !== 'number') {
id = hash(filePath);
fileToIdMap.set(filePath, id);
}
return id;
};
async function mostRecentlyChanged(dir: string) {
const files = await util.promisify<string, string[]>(recursiveReaddir)(dir);
return files
.map((f) => fs.lstatSync(f).ctime)
.reduce((a, b) => (a > b ? a : b), new Date(0));
}
async function getMetroDir() {
let dir = __dirname;
while (true) {
const dirToCheck = path.join(dir, 'node_modules', 'metro');
if (await fs.pathExists(dirToCheck)) return dirToCheck;
const nextDir = path.dirname(dir);
if (!nextDir || nextDir === '' || nextDir === dir) {
break;
}
dir = nextDir;
}
return __dirname;
}
async function compilePlugin(
pluginDetails: PluginDetails,
pluginCache: string,
{force, failSilently}: CompileOptions,
): Promise<CompiledPluginDetails | null> {
const {dir, specVersion, version, main, source, name} = pluginDetails;
const dev = process.env.NODE_ENV !== 'production';
if (specVersion > 1) {
// eslint-disable-next-line no-console
const entry = path.join(dir, main);
@@ -176,37 +133,7 @@ async function compilePlugin(
// eslint-disable-line no-console
console.log(`⚙️ Compiling ${name}...`);
try {
await Metro.runBuild(
{
reporter: {update: () => {}},
projectRoot: dir,
watchFolders: [metroDir || (await metroDirPromise)].concat(
await getWatchFolders(dir),
),
serializer: {
getRunModuleStatement: (moduleID: string) =>
`module.exports = global.__r(${moduleID}).default;`,
createModuleIdFactory,
},
transformer: {
babelTransformerPath: global.electronResolve
? global.electronResolve('flipper-babel-transformer') // when compilation is executing in Electron main process
: require.resolve('flipper-babel-transformer'), // when compilation is is executing in Node.js script
},
resolver: {
sourceExts: ['tsx', 'ts', 'js'],
blacklistRE: /\.native\.js$/,
},
},
{
entry: source,
out: entry,
dev,
sourceMap: true,
minify: false,
resetCache: !dev,
},
);
await runBuild(dir, source, entry);
} catch (e) {
if (failSilently) {
console.error(