Restructured dev workflow docs
Summary: This diff unifies setup and workflow information that was scattered a bit around into one cohesive 'Development workflow' subsection in the 'creating plugins' section of Flipper. Reviewed By: nikoant Differential Revision: D25612288 fbshipit-source-id: 5fa7f2d000fb7ab3e1b5c5a4fc8cc1f209252f41
This commit is contained in:
committed by
Facebook GitHub Bot
parent
19ea20511c
commit
69dae5c8e5
231
docs/extending/desktop-plugin-structure.mdx
Normal file
231
docs/extending/desktop-plugin-structure.mdx
Normal file
@@ -0,0 +1,231 @@
|
||||
---
|
||||
id: desktop-plugin-structure
|
||||
title: Plugin structure
|
||||
---
|
||||
|
||||
import {FbInternalOnly, OssOnly} from 'internaldocs-fb-helpers';
|
||||
import FbNpmDeps from '../fb/adding-npm-dependencies-0.mdx'
|
||||
|
||||
Flipper Desktop plugins have a rigid structure. We recommend to scaffold any new plugin using our scaffolding tooling.
|
||||
|
||||
## Scaffolding a new plugin
|
||||
|
||||
<OssOnly>
|
||||
|
||||
### 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.
|
||||
|
||||
</OssOnly>
|
||||
|
||||
<FbInternalOnly>
|
||||
|
||||
### scarf flipper-plugin
|
||||
|
||||
On a FB machine, new plugins can be scaffolded by running `scarf flipper-plugin`.
|
||||
This takes care of both the Desktop and Client side setup of plugins.
|
||||
Follow the instructions offered by scarf.
|
||||
|
||||
</FbInternalOnly>
|
||||
|
||||
## 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:
|
||||
|
||||
```json
|
||||
{
|
||||
"$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`:
|
||||
|
||||
```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
|
||||
|
||||
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`:
|
||||
|
||||
```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).
|
||||
|
||||
### 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](./create-table-plugin).
|
||||
|
||||
|
||||
## Validation
|
||||
|
||||
<OssOnly>
|
||||
|
||||
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.
|
||||
|
||||
</OssOnly>
|
||||
|
||||
<FbInternalOnly>
|
||||
|
||||
Make sure to address any lint errors shown in the IDE or surfaced on phabricator.
|
||||
To manually run the linter run `yarn lint` in `~/fbsource/xplat/sonar/desktop`.
|
||||
|
||||
</FbInternalOnly>
|
||||
|
||||
<OssOnly>
|
||||
|
||||
## Transpilation and bundling
|
||||
|
||||
Flipper has [tooling for transpiling and bundling](#transpiling-and-bundling) which allows writing plugins in plain ES6 JavaScript or [TypeScript](https://www.typescriptlang.org/).
|
||||
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](#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 `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.
|
||||
|
||||
</OssOnly>
|
||||
|
||||
## npm dependencies
|
||||
|
||||
<OssOnly>
|
||||
|
||||
If you need any dependencies in your plugin, you can install them using `yarn add`.
|
||||
|
||||
</OssOnly>
|
||||
|
||||
<FbNpmDeps />
|
||||
|
||||
<OssOnly>
|
||||
|
||||
## 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.
|
||||
|
||||
</OssOnly>
|
||||
152
docs/extending/dev-setup.mdx
Normal file
152
docs/extending/dev-setup.mdx
Normal file
@@ -0,0 +1,152 @@
|
||||
---
|
||||
id: dev-setup
|
||||
title: Development Setup
|
||||
---
|
||||
|
||||
import {FbInternalOnly, OssOnly} from 'internaldocs-fb-helpers';
|
||||
|
||||
## IDE
|
||||
|
||||
<OssOnly>
|
||||
|
||||
When developing Flipper plugins we recommend the following IDEs:
|
||||
|
||||
1. TypeScript (for Flipper Desktop (plugins)): Visual Studio Code
|
||||
1. Install the "ESLint" (dbaeumer.vscode-eslint) extension from marketplace to enable linting
|
||||
1. Install the "Prettier" (esbenp.prettier-vscode) extension to enable automatic code-formatting
|
||||
1. If for some reason it is not working, the builtin TypeScript extension might be disabled. To enable it, to go to extensions, search for “@builtin typescript” and enable it.
|
||||
|
||||
1. Android Studio (for Android plugins)
|
||||
1. XCode (for iOS plugins)
|
||||
|
||||
</OssOnly>
|
||||
|
||||
<FbInternalOnly>
|
||||
|
||||
### TypeScript
|
||||
|
||||
Flipper Desktop is written in TypeScript.
|
||||
Using our internal "VSCode @ FB" as IDE is strongly recommended (`code-fb`).
|
||||
|
||||
Make sure to install the `[FB-Internal]` "ESLint" and "Pretter" extensions are enabled.
|
||||
|
||||
If for some reason it is not working, the builtin TypeScript extension might be disabled. To enable it, to go to extensions, search for “@builtin typescript” and enable it.
|
||||
|
||||
### Android (Java)
|
||||
|
||||
IntelliJ is the recommended platform. Focussing on a flipper-enabled app should include the flipper modules as expected.
|
||||
|
||||
If you don't have an fbsource checkout (e.g. Whatsapp Team), you can open Android Studio and import project: `fbsource/xplat/sonar`
|
||||
|
||||
If you're having gradle (or other) problems, make sure you're on the latest Android Studio version.
|
||||
|
||||
</FbInternalOnly>
|
||||
|
||||
|
||||
## Running Flipper from source (recommended)
|
||||
|
||||
When developing Flipper plugins we strongly recommend to run from Flipper itself from source as well, as this yields several benefits:
|
||||
|
||||
|
||||
- Automatic transpilation and bundling of loaded plugins: ES6, TypeScript, JSX.
|
||||
- Automatic refresh after code changes.
|
||||
- React and Redux Dev Tools.
|
||||
- [Debugging](debugging) using Chrome Dev Tools or Visual Studio Code.
|
||||
- Additional debug information like React warnings and performance metrics.
|
||||
|
||||
Prerequisites for Flipper development build:
|
||||
- node ≥ 14
|
||||
- yarn ≥ 1.5
|
||||
- git
|
||||
- watchman
|
||||
|
||||
To run Flipper Desktop from source:
|
||||
|
||||
<OssOnly>
|
||||
|
||||
```
|
||||
git clone https://github.com/facebook/flipper.git
|
||||
cd flipper/desktop
|
||||
yarn
|
||||
yarn start
|
||||
```
|
||||
|
||||
Tip: start with `yarn start --fast-refresh` for experimental fast refresh.
|
||||
|
||||
</OssOnly>
|
||||
|
||||
<FbInternalOnly>
|
||||
|
||||
```
|
||||
fbclone fbsource
|
||||
cd ~/fbsource/xplat/sonar/desktop
|
||||
yarn
|
||||
yarn start
|
||||
```
|
||||
|
||||
Tip: start with `yarn start --fast-refresh` for experimental fast refresh.
|
||||
|
||||
Run `code-fb .` in the same directory to open an IDE to hack on Flipper.
|
||||
|
||||
</FbInternalOnly>
|
||||
|
||||
### Startup options
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
## Guidelines for writing TypeScript
|
||||
* **Important:** Use `.tsx` file extension for all TypeScript files (instead of `.ts`)
|
||||
* Prefer `type` for React props and state over interfaces
|
||||
* Don’t prefix interfaces with `I`
|
||||
* Enums, Types and Interfaces use PascalCase (uppercase first letter)
|
||||
* Install 3rd party type definitions as dev dependency (e.g. `yarn add @types/lodash --dev`)
|
||||
|
||||
## Submitting a diff / PR
|
||||
|
||||
Make sure your new functionality is covered with tests, and run `yarn test` or `yarn test --watch` in the `desktop/` directory to verify that they pass.
|
||||
|
||||
See the [testing](testing) page for more details on writing and running test.
|
||||
|
||||
To make sure you don't get any lint/formatting errors, run `yarn lint` before submitting your diff. Some errors (especially formatting errors can be auto-fixed by running `yarn fix`
|
||||
@@ -3,325 +3,6 @@ id: js-setup
|
||||
title: Desktop Plugin Development
|
||||
---
|
||||
|
||||
## Workflow
|
||||
import {Redirect} from '@docusaurus/router';
|
||||
|
||||
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"
|
||||
<Redirect to="/docs/extending/desktop-plugin-structure" />
|
||||
|
||||
46
docs/extending/loading-custom-plugins.mdx
Normal file
46
docs/extending/loading-custom-plugins.mdx
Normal file
@@ -0,0 +1,46 @@
|
||||
---
|
||||
id: loading-custom-plugins
|
||||
title: Dynamically Loading Plugins
|
||||
---
|
||||
|
||||
import {FbInternalOnly, OssOnly} from 'internaldocs-fb-helpers';
|
||||
|
||||
<FbInternalOnly>
|
||||
|
||||
<div class="warning">
|
||||
|
||||
Inside Facebook, plugins sources are stored and loaded from `~/fbsource/xplat/sonar/desktop/plugins`,
|
||||
in which case no further configuration is needed.
|
||||
|
||||
If your team uses Flipper plugins that are stored outside `fbsource`, please follow your team specific instructions.
|
||||
|
||||
</div>
|
||||
|
||||
</FbInternalOnly>
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
<OssOnly>
|
||||
|
||||
Note: when using `npx flipper-pkg init` for scaffolding, as explained in the [tutorial](../tutorial/intro) or on the next page, the path should be configured automatically for you in most cases.
|
||||
|
||||
</OssOnly>
|
||||
|
||||
Typically, the above setup is only needed if you are developing plugins.
|
||||
To consume plugins, it is recommended to use one of the existing [distribution mechanisms](plugin-distribution) instead.
|
||||
63
docs/extending/plugin-distribution.mdx
Normal file
63
docs/extending/plugin-distribution.mdx
Normal file
@@ -0,0 +1,63 @@
|
||||
---
|
||||
id: plugin-distribution
|
||||
title: Plugin Distribution
|
||||
---
|
||||
|
||||
import {FbInternalOnly, OssOnly} from 'internaldocs-fb-helpers';
|
||||
import FbPluginReleases from './fb/desktop-plugin-releases.mdx'
|
||||
|
||||
<OssOnly>
|
||||
|
||||
## 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](desktop-plugin-structure#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"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</OssOnly>
|
||||
|
||||
<FbInternalOnly>
|
||||
|
||||
## Publishing plugins
|
||||
|
||||
<FbPluginReleases />
|
||||
|
||||
</FbInternalOnly>
|
||||
|
||||
## 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"
|
||||
@@ -11,6 +11,18 @@ import FbAndroidTesting from '../fb/android-plugin-development-testing-android-p
|
||||
|
||||
Developer tools are only used if they work. We have built APIs to test plugins.
|
||||
|
||||
## Writing tests
|
||||
|
||||
## Desktop plugins
|
||||
|
||||
Flipper uses [Jest](https://jestjs.io/) as unit testing framework.
|
||||
|
||||
Writing unit tests for Flipper Desktop plugins is covered in detail in the [tutorial](../../docs/tutorial/js-custom#testing-plugin-logic).
|
||||
|
||||
The `flipper-plugin` package provide several [test utilities](../../docs/extending/flipper-plugin#testutils) to make testing more convenient.
|
||||
|
||||
## Client plugins
|
||||
|
||||
<Tabs defaultValue="android" values={[{label: 'Android', value: 'android'}, { label: 'iOS', value: 'ios'}]}>
|
||||
<TabItem value="android">
|
||||
|
||||
@@ -113,3 +125,70 @@ TEST(MyFlipperPluginTests, testDummy) {
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
## Running (Flipper) tests
|
||||
|
||||
### Flipper Desktop
|
||||
|
||||
<OssOnly>
|
||||
|
||||
Run `yarn jest` or `yarn jest --watch` in the `desktop` directory of your Flipper checkout.
|
||||
|
||||
</OssOnly>
|
||||
|
||||
<FbInternalOnly>
|
||||
|
||||
Run `yarn jest` or `yarn jest --watch` in `~/fbsource/xplat/sonar/desktop`
|
||||
|
||||
</FbInternalOnly>
|
||||
|
||||
### Flipper SDK
|
||||
|
||||
#### Android (Java)
|
||||
|
||||
<OssOnly>
|
||||
|
||||
##### Gradle:
|
||||
|
||||
In the root directory of the checkout:
|
||||
|
||||
```
|
||||
./gradlew android:test
|
||||
```
|
||||
|
||||
</OssOnly>
|
||||
|
||||
<FbInternalOnly>
|
||||
|
||||
##### Gradle:
|
||||
|
||||
```
|
||||
cd fbsource/xplat/sonar
|
||||
./gradlew android:test
|
||||
```
|
||||
|
||||
##### Buck:
|
||||
|
||||
I don't know of a way to run them locally 😞 Make a change and submit a diff.
|
||||
|
||||
`buck test ...` should work, but doesn't seem to when run in xplat on mac but they do work on mobile on demand, if you use @mode/server.
|
||||
|
||||
*Debugging note: They do work if you copy the files and BUCK file to* `fbandroid/javatests` *and change the rule from* `sonar_android_test` *to* `robolectric3_test`
|
||||
|
||||
</FbInternalOnly>
|
||||
|
||||
<FbInternalOnly>
|
||||
|
||||
### iOS
|
||||
|
||||
Focus on the plugins, or flipper code you want but with the --with-tests param.
|
||||
|
||||
`arc focus ... --with-tests`
|
||||
|
||||
Then click the <-> icon in xcode and you can run them there.
|
||||
|
||||
</FbInternalOnly>
|
||||
|
||||
### React Native
|
||||
|
||||
See [testing React Native](testing-rn).
|
||||
|
||||
@@ -48,45 +48,7 @@ $ npx flipper-pkg init
|
||||
|
||||
The tool will ask you to provide "id" and "title" for your plugin. Use "sea-mammals" as "id" and "Sea Mammals" as "title". After that the tool will create two files in the directory: `package.json` and `src/index.tsx`.
|
||||
|
||||
Open the `package.json` to check the fields:
|
||||
|
||||
1. "$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.
|
||||
2. "name" must start with "flipper-plugin-"
|
||||
3. "keywords" must contain "flipper-plugin"
|
||||
4. "id" must be the same as used on native side, e.g. returned by getId() method in Android plugin. In our case that is "sea-mammals".
|
||||
5. "flipperBundlerEntry" must point to the source entry point which will be used by "flipper-pkg" to produce the plugin bundle.
|
||||
6. "main" must point to the place where the produced bundle will be written.
|
||||
7. "title" and "icon" are optional fields specifying the plugin item appearance in the Flipper sidebar.
|
||||
|
||||
For instance:
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "https://fbflipper.com/schemas/plugin-package/v2.json",
|
||||
"name": "flipper-plugin-sea-mammals",
|
||||
"id": "sea-mammals",
|
||||
"version": "2.0.0",
|
||||
"main": "dist/bundle.js",
|
||||
"flipperBundlerEntry": "src/index.tsx",
|
||||
"license": "MIT",
|
||||
"keywords": ["flipper-plugin"],
|
||||
"icon": "apps",
|
||||
"title": "Sea Mammals",
|
||||
"category": "Example Plugin",
|
||||
"scripts": {
|
||||
"lint": "flipper-pkg lint",
|
||||
"prepack": "flipper-pkg lint && flipper-pkg bundle"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"flipper": "latest"
|
||||
},
|
||||
"devDependencies": {
|
||||
"flipper": "latest",
|
||||
"flipper-pkg": "latest"
|
||||
}
|
||||
}
|
||||
```
|
||||
*See [package.json](https://github.com/facebook/flipper/blob/master/desktop/plugins/seamammals/package.json)*
|
||||
See [package.json](https://github.com/facebook/flipper/blob/master/desktop/plugins/seamammals/package.json) for an example.
|
||||
|
||||
To ensure there are no errors in the defined plugin, install packages (using `yarn install` or `npm install`) and execute script `lint` (`yarn lint` or `npm run lint`) which shows all the mismatches that should be fixed to make the plugin definition valid.
|
||||
|
||||
|
||||
@@ -79,14 +79,27 @@ module.exports = {
|
||||
'tutorial/js-custom',
|
||||
'tutorial/js-publishing',
|
||||
],
|
||||
'Development workflow': [
|
||||
'extending/dev-setup',
|
||||
'extending/loading-custom-plugins',
|
||||
'extending/desktop-plugin-structure',
|
||||
'extending/testing',
|
||||
'extending/debugging',
|
||||
...fbInternalOnly([
|
||||
'fb/adding-analytics-0',
|
||||
]),
|
||||
'extending/plugin-distribution',
|
||||
],
|
||||
'Desktop plugin APIs': [
|
||||
'extending/flipper-plugin',
|
||||
'extending/styling-components',
|
||||
'extending/create-table-plugin',
|
||||
'extending/search-and-filter',
|
||||
fbInternalOnly({
|
||||
'QPL linting': ['fb/building-a-linter', 'fb/active-linters'],
|
||||
}),
|
||||
...fbInternalOnly([
|
||||
{
|
||||
'QPL linting': ['fb/building-a-linter', 'fb/active-linters'],
|
||||
}
|
||||
]),
|
||||
{
|
||||
'Deprecated APIs': [
|
||||
'extending/ui-components',
|
||||
@@ -97,22 +110,10 @@ module.exports = {
|
||||
'Client plugin APIs': [
|
||||
'extending/create-plugin',
|
||||
'extending/error-handling',
|
||||
'extending/testing',
|
||||
'extending/arch',
|
||||
'extending/client-plugin-lifecycle',
|
||||
'extending/layout-inspector',
|
||||
],
|
||||
Workflow: [
|
||||
'extending/js-setup',
|
||||
'extending/debugging',
|
||||
...fbInternalOnly([
|
||||
'extending/fb/desktop-plugin-releases',
|
||||
'fb/developmentworkflow',
|
||||
'fb/TypeScript',
|
||||
'fb/adding-npm-dependencies-0',
|
||||
'fb/adding-analytics-0',
|
||||
]),
|
||||
],
|
||||
},
|
||||
'fb-internal': {
|
||||
'FB Internal': fbInternalOnly([
|
||||
|
||||
Reference in New Issue
Block a user