diff --git a/desktop/pkg-lib/package.json b/desktop/pkg-lib/package.json index 276a2315b..26c3ab477 100644 --- a/desktop/pkg-lib/package.json +++ b/desktop/pkg-lib/package.json @@ -10,9 +10,11 @@ "bugs": "https://github.com/facebook/flipper/issues", "dependencies": { "flipper-babel-transformer": "0.0.0", + "flipper-plugin-lib": "0.0.0", "fs-extra": "^9.0.1", "metro": "^0.65.2", - "metro-minify-terser": "^0.65.2" + "metro-minify-terser": "^0.65.2", + "npm-packlist": "^2.1.4" }, "devDependencies": { "@types/fs-extra": "^9.0.1", diff --git a/desktop/pkg/src/utils/computePackageChecksum.ts b/desktop/pkg-lib/src/computePackageChecksum.ts similarity index 100% rename from desktop/pkg/src/utils/computePackageChecksum.ts rename to desktop/pkg-lib/src/computePackageChecksum.ts diff --git a/desktop/pkg-lib/src/index.ts b/desktop/pkg-lib/src/index.ts index e5ab0987d..41282807c 100644 --- a/desktop/pkg-lib/src/index.ts +++ b/desktop/pkg-lib/src/index.ts @@ -9,3 +9,4 @@ export {default as runBuild} from './runBuild'; export {default as getWatchFolders} from './getWatchFolders'; +export {default as computePackageChecksum} from './computePackageChecksum'; diff --git a/desktop/pkg-lib/src/runBuild.ts b/desktop/pkg-lib/src/runBuild.ts index cdc7a522f..c6f45ed25 100644 --- a/desktop/pkg-lib/src/runBuild.ts +++ b/desktop/pkg-lib/src/runBuild.ts @@ -11,6 +11,7 @@ import Metro from 'metro'; import getWatchFolders from './getWatchFolders'; import path from 'path'; import fs from 'fs-extra'; +import {getInstalledPluginDetails} from 'flipper-plugin-lib'; let metroDir: string | undefined; const metroDirPromise = getMetroDir().then((dir) => (metroDir = dir)); @@ -30,19 +31,29 @@ async function getMetroDir() { return __dirname; } -export default async function runBuild( - inputDirectory: string, - entry: string, - out: string, - dev: boolean, -) { +export default async function bundlePlugin(pluginDir: string, dev: boolean) { + const stat = await fs.lstat(pluginDir); + if (!stat.isDirectory()) { + throw new Error(`Plugin source ${pluginDir} is not a directory.`); + } + const packageJsonPath = path.join(pluginDir, 'package.json'); + if (!(await fs.pathExists(packageJsonPath))) { + throw new Error( + `package.json is not found in plugin source directory ${pluginDir}.`, + ); + } + const plugin = await getInstalledPluginDetails(pluginDir); + const entry = plugin.source; + const out = path.resolve(pluginDir, plugin.main); + await fs.ensureDir(path.dirname(out)); + const sourceMapUrl = null; // inline source map const baseConfig = await Metro.loadConfig(); const config = Object.assign({}, baseConfig, { reporter: {update: () => {}}, - projectRoot: inputDirectory, + projectRoot: pluginDir, watchFolders: [metroDir || (await metroDirPromise)].concat( - await getWatchFolders(inputDirectory), + await getWatchFolders(pluginDir), ), serializer: { ...baseConfig.serializer, diff --git a/desktop/pkg-lib/tsconfig.json b/desktop/pkg-lib/tsconfig.json index d40807250..21f1c3a3b 100644 --- a/desktop/pkg-lib/tsconfig.json +++ b/desktop/pkg-lib/tsconfig.json @@ -4,7 +4,19 @@ "outDir": "lib", "rootDir": "src" }, - "references": [{"path": "../babel-transformer"}], - "include": ["src"], - "exclude": ["node_modules", "**/__tests__/*"] + "references": [ + { + "path": "../babel-transformer" + }, + { + "path": "../plugin-lib" + } + ], + "include": [ + "src" + ], + "exclude": [ + "node_modules", + "**/__tests__/*" + ] } diff --git a/desktop/pkg/package.json b/desktop/pkg/package.json index 897f6134c..87c295c5b 100644 --- a/desktop/pkg/package.json +++ b/desktop/pkg/package.json @@ -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": { diff --git a/desktop/pkg/src/commands/bundle.ts b/desktop/pkg/src/commands/bundle.ts index db9b9c493..fe7bb0880 100644 --- a/desktop/pkg/src/commands/bundle.ts +++ b/desktop/pkg/src/commands/bundle.ts @@ -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...`); diff --git a/desktop/pkg/src/commands/checksum.ts b/desktop/pkg/src/commands/checksum.ts index d2ca93b0a..f0a4e29b4 100644 --- a/desktop/pkg/src/commands/checksum.ts +++ b/desktop/pkg/src/commands/checksum.ts @@ -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 = diff --git a/desktop/pkg/src/commands/pack.ts b/desktop/pkg/src/commands/pack.ts index 0ac8598ec..44674762f 100644 --- a/desktop/pkg/src/commands/pack.ts +++ b/desktop/pkg/src/commands/pack.ts @@ -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 { 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}`); diff --git a/desktop/scripts/build-plugin.ts b/desktop/scripts/build-plugin.ts index ad12445b0..6b77b2b42 100644 --- a/desktop/scripts/build-plugin.ts +++ b/desktop/scripts/build-plugin.ts @@ -12,27 +12,68 @@ import path from 'path'; import fs from 'fs-extra'; import {execSync} from 'child_process'; import {resolvePluginDir} from './workspaces'; +import {runBuild, computePackageChecksum} from 'flipper-pkg-lib'; +import yargs from 'yargs'; -async function buildPlugin(argv: string[]) { - const pluginName = argv[2]; +const argv = yargs + .usage('yarn build-plugin [args]') + .version(false) + .options({ + plugin: { + description: + 'Plugin ID or path relative to "plugins" dir (e.g. "layout")', + type: 'string', + demandOption: true, + alias: 'p', + }, + version: { + description: 'New version to set', + type: 'string', + alias: 'v', + }, + checksum: { + description: + 'Checksum of the previous plugin package which is used to determine whether the plugin is changed or not. If it is not changed, it will not be packaged.', + type: 'string', + alias: 'c', + }, + output: { + description: 'Where to save the plugin package', + type: 'string', + alias: 'o', + }, + }) + .help() + .strict() + .parse(process.argv.slice(1)); + +async function buildPlugin() { + const pluginName = argv.plugin; + const previousChecksum = argv.checksum; const pluginDir = await resolvePluginDir(pluginName); - const outputFileArg = argv.length > 3 ? argv[3] : null; - const outputFile = outputFileArg - ? path.resolve(outputFileArg) - : path.join( - distDir, - 'plugins', - path.relative(pluginsDir, pluginDir) + '.tgz', - ); - await fs.ensureDir(path.dirname(outputFile)); - await fs.remove(outputFile); - const bundleCmd = `yarn flipper-pkg bundle "${pluginDir}" --production`; - const packCmd = `yarn pack --cwd "${pluginDir}" --filename ${outputFile}`; - execSync(bundleCmd, {cwd: rootDir, stdio: 'inherit'}); - execSync(packCmd, {cwd: rootDir, stdio: 'inherit'}); + const outputFileArg = argv.output; + await runBuild(pluginDir, false); + const checksum = await computePackageChecksum(pluginDir); + if (previousChecksum !== checksum && argv.version) { + console.log(`Plugin changed. Packaging new version ${argv.version}...`); + const outputFile = outputFileArg + ? path.resolve(outputFileArg) + : path.join( + distDir, + 'plugins', + path.relative(pluginsDir, pluginDir) + '.tgz', + ); + await fs.ensureDir(path.dirname(outputFile)); + await fs.remove(outputFile); + const versionCmd = `yarn version --cwd "${pluginDir}" --new-version ${argv.version}`; + execSync(versionCmd, {cwd: rootDir, stdio: 'inherit'}); + const packCmd = `yarn pack --cwd "${pluginDir}" --filename ${outputFile}`; + execSync(packCmd, {cwd: rootDir, stdio: 'inherit'}); + await fs.writeFile(outputFile + '.hash', checksum); + } } -buildPlugin(process.argv) +buildPlugin() .then(() => { process.exit(0); })