added simple watch mode

Summary:
Added a watch mode to the bundle command of flipper plugins. This makes it easy to test develop plugins locally, even when you are using a production build of flipper, which lowers the barrier of developing / fixing plugins.

opted for `fs.watch` over watchman to avoid some overengineering:
1. pkg / pkg-lib don't have the watchman utilities that would be needed for this. I wasn't sure if I could move those over from `static` without breaking the bootstrapping process
2. watchman is often a nuisance on non FB machines that aren't set up for it. fs.watch in contrast doesn't have any further dependencies or setup requirements, and is much more likely to work ootb.
3. since we watch only the `src` folder we don't really need the watchman optimizations. (so for a package.json change people would have to restart, but I don't think that is much of a problem).

Reviewed By: jknoxville

Differential Revision: D21523814

fbshipit-source-id: b1de72b7d01c6fc50cb8ce5709f54f8019eb89e4
This commit is contained in:
Michel Weststrate
2020-05-19 05:31:05 -07:00
committed by Facebook GitHub Bot
parent 1e309abe4f
commit 080085e788
2 changed files with 56 additions and 4 deletions

View File

@@ -7,7 +7,7 @@
* @format
*/
import {Command} from '@oclif/command';
import {Command, flags} from '@oclif/command';
import {args} from '@oclif/parser';
import fs from 'fs-extra';
import path from 'path';
@@ -28,8 +28,12 @@ export default class Bundle extends Command {
},
];
public static flags = {
watch: flags.boolean(),
};
public async run() {
const {args} = this.parse(Bundle);
const {args, flags} = this.parse(Bundle);
const inputDirectory: string = path.resolve(process.cwd(), args.directory);
const stat = await fs.lstat(inputDirectory);
if (!stat.isDirectory()) {
@@ -44,6 +48,53 @@ export default class Bundle extends Command {
const plugin = await getPluginDetails(inputDirectory);
const out = path.resolve(inputDirectory, plugin.main);
await fs.ensureDir(path.dirname(out));
await runBuild(inputDirectory, plugin.source, out);
const success = await runBuildOnce(inputDirectory, plugin.source, out);
if (!flags.watch) {
process.exit(success ? 0 : 1);
} else {
enterWatchMode(inputDirectory, plugin.source, out);
}
}
}
async function runBuildOnce(
inputDirectory: string,
source: string,
out: string,
) {
try {
await runBuild(inputDirectory, source, out);
console.log('✅ Build succeeded');
return true;
} catch (e) {
console.error(e);
console.error('🥵 Build failed');
return false;
}
}
function enterWatchMode(inputDirectory: string, source: string, out: string) {
console.log(`⏳ Waiting for changes...`);
let isBuilding = false;
let pendingChanges = false;
fs.watch(
path.join(inputDirectory, 'src'),
{
recursive: true,
},
async () => {
pendingChanges = true;
if (isBuilding) {
return; // prevent kicking of a second build
}
isBuilding = true;
while (pendingChanges) {
pendingChanges = false;
await runBuildOnce(inputDirectory, source, out);
}
isBuilding = false;
console.log(`⏳ Waiting for changes...`);
},
);
}

View File

@@ -14,7 +14,8 @@
"scripts": {
"lint": "flipper-pkg lint",
"prepack": "flipper-pkg lint && flipper-pkg bundle",
"build": "flipper-pkg bundle"
"build": "flipper-pkg bundle",
"watch": "flipper-pkg bundle --watch"
},
"peerDependencies": {
"flipper": "latest"