Performance improvements for "build-plugin" task
Summary: Few improvements for "build-plugin" task which together with Sandcastle command changes (D26872427) helps to build all plugins in CI ~30% faster if most of them has not changed (which is usually the case): 1) compute package checksum in the same script to not call additional yarn scripts for each plugin 2) avoid packaging plugin if it's checksum has not changed since last release Reviewed By: mweststrate Differential Revision: D26872253 fbshipit-source-id: 968102d32a1550ea7503f1169f0ef2863296383f
This commit is contained in:
committed by
Facebook GitHub Bot
parent
5df0fd6e52
commit
baeb8ba5be
@@ -25,7 +25,6 @@
|
||||
"fs-extra": "^9.0.1",
|
||||
"inquirer": "^7.3.3",
|
||||
"lodash": "^4.17.19",
|
||||
"npm-packlist": "^2.1.4",
|
||||
"recursive-readdir": "^2.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -12,7 +12,6 @@ import {args} from '@oclif/parser';
|
||||
import fs from 'fs-extra';
|
||||
import path from 'path';
|
||||
import {runBuild} from 'flipper-pkg-lib';
|
||||
import {getInstalledPluginDetails} from 'flipper-plugin-lib';
|
||||
|
||||
export default class Bundle extends Command {
|
||||
public static description = 'transpiles and bundles plugin';
|
||||
@@ -45,42 +44,18 @@ export default class Bundle extends Command {
|
||||
public async run() {
|
||||
const {args, flags} = this.parse(Bundle);
|
||||
const inputDirectory: string = path.resolve(process.cwd(), args.directory);
|
||||
const stat = await fs.lstat(inputDirectory);
|
||||
if (!stat.isDirectory()) {
|
||||
this.error(`Plugin source ${inputDirectory} is not a directory.`);
|
||||
}
|
||||
const packageJsonPath = path.join(inputDirectory, 'package.json');
|
||||
if (!(await fs.pathExists(packageJsonPath))) {
|
||||
this.error(
|
||||
`package.json is not found in plugin source directory ${inputDirectory}.`,
|
||||
);
|
||||
}
|
||||
const plugin = await getInstalledPluginDetails(inputDirectory);
|
||||
const out = path.resolve(inputDirectory, plugin.main);
|
||||
await fs.ensureDir(path.dirname(out));
|
||||
|
||||
const success = await runBuildOnce(
|
||||
inputDirectory,
|
||||
plugin.source,
|
||||
out,
|
||||
!flags.production,
|
||||
);
|
||||
const success = await runBuildOnce(inputDirectory, !flags.production);
|
||||
if (!flags.watch) {
|
||||
process.exit(success ? 0 : 1);
|
||||
} else {
|
||||
enterWatchMode(inputDirectory, plugin.source, out, !flags.production);
|
||||
enterWatchMode(inputDirectory, !flags.production);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function runBuildOnce(
|
||||
inputDirectory: string,
|
||||
source: string,
|
||||
out: string,
|
||||
dev: boolean,
|
||||
) {
|
||||
async function runBuildOnce(inputDirectory: string, dev: boolean) {
|
||||
try {
|
||||
await runBuild(inputDirectory, source, out, dev);
|
||||
await runBuild(inputDirectory, dev);
|
||||
console.log('✅ Build succeeded');
|
||||
return true;
|
||||
} catch (e) {
|
||||
@@ -90,12 +65,7 @@ async function runBuildOnce(
|
||||
}
|
||||
}
|
||||
|
||||
function enterWatchMode(
|
||||
inputDirectory: string,
|
||||
source: string,
|
||||
out: string,
|
||||
dev: boolean,
|
||||
) {
|
||||
function enterWatchMode(inputDirectory: string, dev: boolean) {
|
||||
console.log(`⏳ Waiting for changes...`);
|
||||
let isBuilding = false;
|
||||
let pendingChanges = false;
|
||||
@@ -112,7 +82,7 @@ function enterWatchMode(
|
||||
isBuilding = true;
|
||||
while (pendingChanges) {
|
||||
pendingChanges = false;
|
||||
await runBuildOnce(inputDirectory, source, out, dev);
|
||||
await runBuildOnce(inputDirectory, dev);
|
||||
}
|
||||
isBuilding = false;
|
||||
console.log(`⏳ Waiting for changes...`);
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
import {Command} from '@oclif/command';
|
||||
import {args} from '@oclif/parser';
|
||||
import path from 'path';
|
||||
import computePackageChecksum from '../utils/computePackageChecksum';
|
||||
import {computePackageChecksum} from 'flipper-pkg-lib';
|
||||
|
||||
export default class Lint extends Command {
|
||||
public static description =
|
||||
|
||||
@@ -10,13 +10,12 @@
|
||||
import {Command, flags} from '@oclif/command';
|
||||
import {args} from '@oclif/parser';
|
||||
import {promises as fs} from 'fs';
|
||||
import {mkdirp, pathExists, readJSON, ensureDir} from 'fs-extra';
|
||||
import {mkdirp, pathExists, readJSON} from 'fs-extra';
|
||||
import * as inquirer from 'inquirer';
|
||||
import * as path from 'path';
|
||||
import * as yarn from '../utils/yarn';
|
||||
import cli from 'cli-ux';
|
||||
import {runBuild} from 'flipper-pkg-lib';
|
||||
import {getInstalledPluginDetails} from 'flipper-plugin-lib';
|
||||
|
||||
async function deriveOutputFileName(inputDirectory: string): Promise<string> {
|
||||
const packageJson = await readJSON(path.join(inputDirectory, 'package.json'));
|
||||
@@ -115,14 +114,8 @@ export default class Pack extends Command {
|
||||
await yarn.install(inputDirectory);
|
||||
cli.action.stop();
|
||||
|
||||
cli.action.start('Reading plugin details');
|
||||
const plugin = await getInstalledPluginDetails(inputDirectory);
|
||||
const out = path.resolve(inputDirectory, plugin.main);
|
||||
cli.action.stop(`done. Source: ${plugin.source}. Main: ${plugin.main}.`);
|
||||
|
||||
cli.action.start(`Compiling`);
|
||||
await ensureDir(path.dirname(out));
|
||||
await runBuild(inputDirectory, plugin.source, out, parsedFlags.production);
|
||||
await runBuild(inputDirectory, parsedFlags.production);
|
||||
cli.action.stop();
|
||||
|
||||
cli.action.start(`Packing to ${outputFile}`);
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
/**
|
||||
* 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 packlist from 'npm-packlist';
|
||||
import path from 'path';
|
||||
import crypto from 'crypto';
|
||||
import fs from 'fs-extra';
|
||||
|
||||
export default async function computePackageChecksum(
|
||||
dir: string,
|
||||
): Promise<string> {
|
||||
const hash = crypto.createHash('sha1');
|
||||
hash.setEncoding('hex');
|
||||
const files = (await packlist({path: dir})).sort();
|
||||
for (const file of files) {
|
||||
// add hash of relative file path
|
||||
hash.write(process.platform === 'win32' ? file.replace(/\\/g, '/') : file);
|
||||
|
||||
const filePath = path.resolve(dir, file);
|
||||
|
||||
if (file === 'package.json') {
|
||||
// add hash of package.json with version set to "0.0.0" to avoid changing hash when only version changed
|
||||
const packageJson = await fs.readJson(filePath);
|
||||
if (packageJson.version) {
|
||||
packageJson.version = '0.0.0';
|
||||
}
|
||||
hash.write(JSON.stringify(packageJson));
|
||||
} else {
|
||||
// add hash of file content
|
||||
const stream = fs.createReadStream(filePath);
|
||||
try {
|
||||
stream.pipe(hash, {end: false});
|
||||
await new Promise((resolve, reject) => {
|
||||
stream.once('end', resolve);
|
||||
stream.once('error', reject);
|
||||
});
|
||||
} finally {
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
hash.end();
|
||||
return hash.read();
|
||||
}
|
||||
Reference in New Issue
Block a user