Summary: This updates the docs of Flipper to use Sandy, rather than `FlipperPlugin` class. Restructured the docs a bit as a result. Reviewed By: passy Differential Revision: D24991285 fbshipit-source-id: 66d5760c25cf9cf3983515433dfd64348d51db3d
328 lines
15 KiB
Plaintext
328 lines
15 KiB
Plaintext
---
|
|
id: js-setup
|
|
title: Desktop Plugin Development
|
|
---
|
|
|
|
## Workflow
|
|
|
|
In a nutshell, the workflow for creating Flipper Desktop Plugin is the following:
|
|
|
|
1. [To make your custom plugins discoverable by Flipper](#dynamically-loading-plugins), create a directory to contain them, e.g. `~/flipper-plugins`, and add this path to the `pluginPaths` property in the Flipper config (`~/.flipper/config.json`).
|
|
2. Create a directory for your plugin inside the directory created at step 1, e.g. `~/flipper-plugins/my-plugin`.
|
|
3. [Define your plugin](#plugin-definition) in the directory created at step 2.
|
|
4. [Start a development build of Flipper](#development-build) which will automatically [transpile, bundle and load](#transpiling-and-bundling) the defined plugin, as well as all other plugins found in the directories specified as `pluginPaths` in the Flipper config.
|
|
5. [Debug your plugin](debugging), make necessary changes and verify them in the running Flipper development build instance which will re-load the changed components automatically.
|
|
6. If you want to be sure the plugin works as expected with a release build, you can [package it as a tarball](#packaging-to-file) and [install it from the file system](#installation-from-file) into a released version of Flipper.
|
|
7. Finally, [bundle the plugin and publish it to npm](#publishing-to-npm), so it can be discovered and installed by any Flipper user.
|
|
|
|
## Dynamically Loading Plugins
|
|
|
|
Flipper loads and runs plugins it finds in a configurable location. The paths searched are specified in `~/.flipper/config.json`. These paths, `pluginPaths`, should contain one folder for each of the plugins it stores. An example config setting and plugin file structure is shown below:
|
|
|
|
`~/.flipper/config.json`:
|
|
```
|
|
{
|
|
...,
|
|
"pluginPaths": ["~/flipper-plugins"]
|
|
}
|
|
```
|
|
Plugin File example structure:
|
|
```
|
|
~ flipper-plugins/
|
|
my-plugin/
|
|
package.json
|
|
src/index.tsx
|
|
dist/bundle.js
|
|
```
|
|
|
|
## Plugin Definition
|
|
|
|
### flipper-pkg
|
|
|
|
CLI tool `flipper-pkg` helps to initialize, validate, and package Flipper desktop plugins.
|
|
|
|
The tool is published to npm and can be installed as a `devDependency` for the plugin package, or as a global CLI tool:
|
|
```
|
|
yarn global add flipper-pkg
|
|
```
|
|
or
|
|
```
|
|
npm install flipper-pkg --global
|
|
```
|
|
|
|
### Package Format
|
|
|
|
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
|
|
|
|
The best way to initialize a JS plugin is to create a directory, and run `flipper-pkg init` inside it ("flipper-pkg" should be installed globally before that). It will ask few questions and initialize the plugin for you.
|
|
|
|
After `flipper-pkg init` 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"
|
|
}
|
|
}
|
|
```
|
|
|
|
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`:
|
|
|
|
```js
|
|
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](./js-plugin-api.mdx).
|
|
|
|
## Anatomy of a Desktop plugin
|
|
|
|
A sandy plugin always exposes two elements from its entry module (typically `src/index.tsx`): `plugin` and `Component`:
|
|
|
|
```typescript
|
|
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](../tutorial/js-custom).
|
|
|
|
### 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:
|
|
|
|
```typescript
|
|
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](./flipper-plugin#devicepluginclient).
|
|
|
|
|
|
### 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
|
|
|
|
Flipper has [tooling for transpiling and bundling](#transpiling-and-bundling) which allows writing plugins in plain ES6 JavaScript, [Flow](https://flow.org/) or [TypeScript](https://www.typescriptlang.org/) but 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.
|
|
|
|
### npm dependencies
|
|
|
|
If you need any dependencies in your plugin, you can install them using `yarn add`.
|
|
|
|
## Migration to the 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.
|
|
|
|
## Development Build
|
|
|
|
A Flipper development build should be used for plugin debugging. It is also used for Flipper core development and provides the following features:
|
|
|
|
- Automatic transpilation and bundling of loaded plugins: ES6, Flow, TypeScript, JSX.
|
|
- Automatic refresh after code changes.
|
|
- React and Redux Dev Tools.
|
|
- [Debugging](debugging) using Chrome Dev Tools or Visual Studio Code.
|
|
|
|
Prerequisites for Flipper development build:
|
|
- node ≥ 8
|
|
- yarn ≥ 1.5
|
|
- git
|
|
- watchman
|
|
|
|
To start a development build, clone the Flipper repository, install the dependencies and execute the `start` script:
|
|
|
|
```
|
|
git clone https://github.com/facebook/flipper.git
|
|
cd flipper/desktop
|
|
yarn
|
|
yarn start
|
|
```
|
|
|
|
You can use several options to customise development build instance. They can be provided as command-line args or environment variables.
|
|
You can check all of them by executing `yarn start --help`:
|
|
```
|
|
yarn start [args]
|
|
|
|
Options:
|
|
--embedded-plugins Enables embedding of plugins into Flipper bundle. If it
|
|
disabled then only installed plugins are loaded. The
|
|
flag is enabled by default. Env var
|
|
FLIPPER_NO_EMBEDDED_PLUGINS is equivalent to the
|
|
command-line option "--no-embedded-plugins". [boolean]
|
|
--fast-refresh Enable Fast Refresh - quick reload of UI component
|
|
changes without restarting Flipper. The flag is disabled
|
|
by default. Env var FLIPPER_FAST_REFRESH is equivalent
|
|
to the command-line option "--fast-refresh". [boolean]
|
|
--plugin-auto-update [FB-internal only] Enable plugin auto-updates. The flag
|
|
is disabled by default in dev mode. Env var
|
|
FLIPPER_NO_PLUGIN_AUTO_UPDATE is equivalent to the
|
|
command-line option "--no-plugin-auto-update" [boolean]
|
|
--enabled-plugins Load only specified plugins and skip loading rest. This
|
|
is useful when you are developing only one or few
|
|
plugins. Plugins to load can be specified as a
|
|
comma-separated list with either plugin id or name used
|
|
as identifier, e.g. "--enabled-plugins
|
|
network,inspector". The flag is not provided by default
|
|
which means that all plugins loaded. [array]
|
|
--open-dev-tools Open Dev Tools window on startup. The flag is disabled
|
|
by default. Env var FLIPPER_OPEN_DEV_TOOLS is equivalent
|
|
to the command-line option "--open-dev-tools". [boolean]
|
|
--dev-server-port Dev server port. 3000 by default. Env var "PORT=3001" is
|
|
equivalent to the command-line option "--dev-server-port
|
|
3001". [number] [default: 3000]
|
|
--version Show version number [boolean]
|
|
--help Show help [boolean]
|
|
```
|
|
|
|
You can also create file `.env` in `desktop` subfolder and specify any environment variables to load them automatically on `yarn start` so you don't need to pass command-line args every time, e.g.:
|
|
```
|
|
FLIPPER_FAST_REFRESH=true
|
|
FLIPPER_OPEN_DEV_TOOLS=true
|
|
FLIPPER_ENABLED_PLUGINS=flipper-messages,network,inspector
|
|
```
|
|
|
|
## Transpiling and Bundling
|
|
|
|
As we already mentioned, the [Flipper development build](#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](#packaging-and-publishing) using [flipper-pkg](https://classic.yarnpkg.com/en/package/flipper-pkg). This utility applies the same modifications as the plugin loader of the development build.
|
|
|
|
The tool is published to npm and can be installed as a `devDependency` for the plugin package, or as a global CLI tool:
|
|
```
|
|
yarn global add flipper-pkg
|
|
```
|
|
|
|
Then, to bundle the plugin, execute the following command in its folder:
|
|
```
|
|
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.
|
|
|
|
## Packaging and Publishing
|
|
|
|
### Publishing to npm
|
|
|
|
Flipper plugins are essentially standard npm packages. So you can publish them by executing `yarn publish` or `npm publish` in the plugin directory. The only requirements are:
|
|
|
|
1. `package.json` and code [must follow the Flipper plugin specification](#plugin-definition)
|
|
2. code must be bundled using "flipper-pkg" before packing or publishing. This can be done by executing `flipper-pkg bundle` on `prepack` step:
|
|
```
|
|
{
|
|
...
|
|
"devDependencies": {
|
|
...
|
|
"flipper-pkg": "latest"
|
|
},
|
|
"scripts": {
|
|
...
|
|
"prepack": "flipper-pkg bundle"
|
|
}
|
|
}
|
|
```
|
|
|
|
### Packaging to File
|
|
|
|
To package plugin as a tarball, you can use the same command as for packaging any other npm package, e.g. `yarn pack` or `npm pack`.
|
|
|
|
"flipper-pkg" also provides a convenient command `pack` which:
|
|
|
|
1. Installs the plugin dependencies
|
|
2. Bundles the plugin
|
|
3. Creates the tarball and saves it at the specified location
|
|
|
|
E.g. to package plugin located at `~/flipper-plugins/my-plugin` to `~/Desktop`, execute the following command:
|
|
```
|
|
flipper-pkg pack ~/flipper-plugins/my-plugin -o ~/Desktop
|
|
```
|
|
|
|
### Installation from File
|
|
|
|
It is possible to install plugins into Flipper from tarballs. This is useful in cases when you need to try a plugin version which is not published to npm, or if you want to distribute plugin privately:
|
|
|
|
1. Launch Flipper
|
|
2. Click the "Manage Plugins" button in the bottom-left corner
|
|
3. Select the "Install Plugins" tab in the opened sheet
|
|
4. Specify the path to the plugin package (or just drag and drop it) and click "Install"
|