Plugin structure

Flipper Desktop plugins have a rigid structure. We recommend to scaffold any new plugin using our scaffolding tooling.

Scaffolding a new plugin

flipper-pkg

The CLI tool flipper-pkg helps to initialize, validate, and package Flipper desktop plugins.

To scaffold a new plugin run npx flipper-pkg init in the directory where you want to store the plugin sources. Note that this should typically not be inside a Flipper checkout, but rather a fresh directory which you can put under your own source control.

Desktop Plugin structure

All Flipper Desktop plugins must be self-contained in a directory. This directory must contain at a minimum package.json and entry source file, e.g.:

  • package.json
  • src/index.tsx

After scaffolding a new plugin has finished, you should have files package.json and src/index.tsx files in the directory. The first file is the plugin package manifest and the second is the entry point to your plugin. An example package.json file could look like this:

{
"$schema": "https://fbflipper.com/schemas/plugin-package/v2.json",
"name": "flipper-plugin-myplugin",
"id": "myplugin",
"version": "1.0.0",
"main": "dist/bundle.js",
"flipperBundlerEntry": "src/index.tsx",
"license": "MIT",
"keywords": ["flipper-plugin"],
"title": "My Plugin",
"icon": "apps",
"bugs": {
"email": "you@example.com"
},
"scripts": {
"lint": "flipper-pkg lint",
"prepack": "flipper-pkg lint && flipper-pkg bundle"
},
"peerDependencies": {
"flipper": "latest",
"flipper-plugin": "latest"
},
"devDependencies": {
"flipper": "latest",
"flipper-plugin": "latest",
"flipper-pkg": "latest",
"react": "latest",
"antd": "latest
}
}

Important attributes of package.json:

  • $schema must contain URI identifying scheme according to which the plugin is defined. Currently, Flipper supports plugins defined by the specification version 2 (https://fbflipper.com/schemas/plugin-package/v2.json), while version 1 is being deprecated.

  • name Npm package name. Should start with flipper-plugin- by convention, so Flipper plugins can be easily found on npm.

  • id Used as the plugin native identifier and must match the mobile plugin identifier, e.g. returned by getId method of your Java plugin.

  • main Points to the plugin bundle which will be loaded by Flipper. The "flipper-pkg" utility uses this field to determine output location during plugin bundling.

  • flipperBundlerEntry Points to the source entry point which will be used for plugin code bundling. "flipper-pkg" takes the path specified in flipperBundlerEntry as source, transpiles and bundles it, and saves the output to the path specified in main.

  • keywords The field must contain the flipper-plugin keyword, otherwise Flipper won't discover the plugin. Additionally, the field can also contain any other keywords for better plugin discoverability.

  • title Shown in the main sidebar as the human-readable name of the plugin.

  • icon Determines the plugin icon which is displayed in the main sidebar. The list of available icons is static for now: https://github.com/facebook/flipper/blob/master/desktop/static/icons.json.

  • bugs Specify an email and/or url, where plugin bugs should be reported.

In index.tsx you will define the plugin in JavaScript.

Example index.tsx:

export function plugin(client) {
return {};
}
export function Component() {
return 'hello world';
}

Some public plugins will use a FlipperPlugin base class. This format is deprecated but the documentation can still be found here.

Anatomy of a Desktop plugin

Flipper Desktop plugins come in three possible flavors:

  1. Client plugins: A plugin that connects to a specific client plugin running in an app (recommended)
  2. Device plugins: A plugin that doesn't connect to a specific client and doesn't have a native counter part, but rather shows data about the device obtained through some other means, like device logs, device temperatures, etc.
  3. Table plugin: A simplified version of a client plugin, that merely displays incoming data from a client plugin in a table.

Creating a Client Plugin

A plugin always exposes two elements from its entry module (typically src/index.tsx): plugin and Component:

import {PluginClient} from 'flipper-plugin';
export function plugin(client: PluginClient) {
return {}; // API exposed from this plugin
}
export function Component() {
// Plugin UI
return <h1>Welcome to my first plugin</h1>;
}

A further guide on how to write custom Flipper plugins can be found here: tutorial.

Creating a Device Plugin

Flipper also supports so-called device plugins - plugins that are available for an entire device - but don't receive a connection to a running app, so are a bit more limited in general. Their entry module anatomy is:

import {DevicePluginClient} from 'flipper-plugin';
export function supportsDevice(device: Device) {
// based on the device meta-data,
// determine whether this plugin should be enabled
return true;
}
export function devicePlugin(client: DevicePluginClient) {
return {}; // API exposed from this plugin
}
export function Component() {
// Plugin UI
return <h1>Welcome to my first plugin</h1>;
}

Device plugins work in general similar to normal client plugins, so aren't worked out in detail in this document. The available APIs for device plugins are listed here.

Creating a simple table plugin

Flipper provides a standard abstraction to render data received from a Client plugin in a table, see creating a table plugin.

Validation

Plugin definition can be validated using command flipper-pkg lint. The command shows all the mismatches which should be fixed to make plugin definition valid.

Transpilation and bundling

Flipper has tooling for transpiling and bundling which allows writing plugins in plain ES6 JavaScript or TypeScript. We recommend you use TypeScript for the best development experience. We also recommend you use the file extension .tsx when using TypeScript which adds support for inline React expressions.

As we already mentioned, the Flipper development build automatically transpiles and bundles plugins on loading. It is capable of all the ES6 goodness, Flow annotations, TypeScript, as well as JSX and applies the required babel-transforms.

The Flipper release build, in contrast, does not transpile or bundle plugins on loading. For production usage, plugins should be bundled before publishing using flipper-pkg. This utility applies the same modifications as the plugin loader of the development build.

The flipper-pkg tool is published to npm and should be installed as a devDependency for the plugin package.

Then, to bundle the plugin, execute the following command in its folder:

yarn flipper-pkg bundle

This command reads the package.json, takes the path specified in the flipperBundleEntry field as entry point, transpiles and bundles all the required code, and outputs the produced bundle to the path specified in field main.

You can get the list of other available commands by invoking flipper-pkg help, and get detailed description for any command by invoking flipper-pkg help [COMMAND]. You can also check README on npmjs.com for usage details: https://www.npmjs.com/package/flipper-pkg.

npm dependencies

If you need any dependencies in your plugin, you can install them using yarn add.

Migration to new Plugin Specification

Flipper plugins are defined according to the specification. As with any specification, it is evolving, so new versions of it can be released. Currently Flipper supports plugins defined using version 2 of specification which is described in this page. Previous version of specification is being deprecated, and we encourage all the plugins still using it to migrate.

The main difference of version 2 is that plugins are transpiled and bundled before packaging, while in version 1 this was done in run-time on plugin installation. There are no plugin API changes, so only the package.json changes are required to migrate.

The easiest way for migration is using of command flipper-pkg migrate. It will automatically migrate your plugin definition to the latest version.