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:
Michel Weststrate
2020-12-17 07:38:44 -08:00
committed by Facebook GitHub Bot
parent 19ea20511c
commit 69dae5c8e5
8 changed files with 591 additions and 376 deletions

View 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>

View 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
* Dont 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`

View File

@@ -3,325 +3,6 @@ id: js-setup
title: Desktop Plugin Development title: Desktop Plugin Development
--- ---
## Workflow import {Redirect} from '@docusaurus/router';
In a nutshell, the workflow for creating Flipper Desktop Plugin is the following: <Redirect to="/docs/extending/desktop-plugin-structure" />
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"

View 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.

View 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"

View File

@@ -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. 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'}]}> <Tabs defaultValue="android" values={[{label: 'Android', value: 'android'}, { label: 'iOS', value: 'ios'}]}>
<TabItem value="android"> <TabItem value="android">
@@ -113,3 +125,70 @@ TEST(MyFlipperPluginTests, testDummy) {
</TabItem> </TabItem>
</Tabs> </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).

View File

@@ -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`. 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: See [package.json](https://github.com/facebook/flipper/blob/master/desktop/plugins/seamammals/package.json) for an example.
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)*
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. 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.

View File

@@ -79,14 +79,27 @@ module.exports = {
'tutorial/js-custom', 'tutorial/js-custom',
'tutorial/js-publishing', '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': [ 'Desktop plugin APIs': [
'extending/flipper-plugin', 'extending/flipper-plugin',
'extending/styling-components', 'extending/styling-components',
'extending/create-table-plugin', 'extending/create-table-plugin',
'extending/search-and-filter', 'extending/search-and-filter',
fbInternalOnly({ ...fbInternalOnly([
'QPL linting': ['fb/building-a-linter', 'fb/active-linters'], {
}), 'QPL linting': ['fb/building-a-linter', 'fb/active-linters'],
}
]),
{ {
'Deprecated APIs': [ 'Deprecated APIs': [
'extending/ui-components', 'extending/ui-components',
@@ -97,22 +110,10 @@ module.exports = {
'Client plugin APIs': [ 'Client plugin APIs': [
'extending/create-plugin', 'extending/create-plugin',
'extending/error-handling', 'extending/error-handling',
'extending/testing',
'extending/arch', 'extending/arch',
'extending/client-plugin-lifecycle', 'extending/client-plugin-lifecycle',
'extending/layout-inspector', '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': {
'FB Internal': fbInternalOnly([ 'FB Internal': fbInternalOnly([