diff --git a/docs/extending/desktop-plugin-structure.mdx b/docs/extending/desktop-plugin-structure.mdx new file mode 100644 index 000000000..379cec0f1 --- /dev/null +++ b/docs/extending/desktop-plugin-structure.mdx @@ -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 + + + +### 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. + + + + + +### 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. + + + +## 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

Welcome to my first plugin

; +} +``` + +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

Welcome to my first plugin

; +} +``` + +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 + + + +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. + + + + + +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`. + + + + + +## 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. + + + +## npm dependencies + + + +If you need any dependencies in your plugin, you can install them using `yarn add`. + + + + + + + +## Migration to new Plugin Specification + +Flipper plugins are defined according to the specification. As with any specification, it is evolving, so new versions of it can be released. Currently Flipper supports plugins defined using version 2 of specification which is described in this page. Previous version of specification is being deprecated, and we encourage all the plugins still using it to migrate. + +The main difference of version 2 is that plugins are transpiled and bundled before packaging, while in version 1 this was done in run-time on plugin installation. There are no plugin API changes, so only the `package.json` changes are required to migrate. + +The easiest way for migration is using of command `flipper-pkg migrate`. It will automatically migrate your plugin definition to the latest version. + + diff --git a/docs/extending/dev-setup.mdx b/docs/extending/dev-setup.mdx new file mode 100644 index 000000000..749950b84 --- /dev/null +++ b/docs/extending/dev-setup.mdx @@ -0,0 +1,152 @@ +--- +id: dev-setup +title: Development Setup +--- + +import {FbInternalOnly, OssOnly} from 'internaldocs-fb-helpers'; + +## IDE + + + +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) + + + + + +### 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. + + + + +## 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: + + + +``` +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. + + + + + +``` +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. + + + +### 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` diff --git a/docs/extending/jssetup.mdx b/docs/extending/jssetup.mdx index 2ed2210c1..84c70ef55 100644 --- a/docs/extending/jssetup.mdx +++ b/docs/extending/jssetup.mdx @@ -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

Welcome to my first plugin

; -} -``` - -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

Welcome to my first plugin

; -} -``` - -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" + diff --git a/docs/extending/loading-custom-plugins.mdx b/docs/extending/loading-custom-plugins.mdx new file mode 100644 index 000000000..d4d637e0e --- /dev/null +++ b/docs/extending/loading-custom-plugins.mdx @@ -0,0 +1,46 @@ +--- +id: loading-custom-plugins +title: Dynamically Loading Plugins +--- + +import {FbInternalOnly, OssOnly} from 'internaldocs-fb-helpers'; + + + +
+ +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. + +
+ +
+ +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 +``` + + + +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. + + + +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. diff --git a/docs/extending/plugin-distribution.mdx b/docs/extending/plugin-distribution.mdx new file mode 100644 index 000000000..12d6a77cc --- /dev/null +++ b/docs/extending/plugin-distribution.mdx @@ -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' + + + +## 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" + } + } + ``` + + + + + +## Publishing plugins + + + + + +## 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" diff --git a/docs/extending/testing.mdx b/docs/extending/testing.mdx index c21681bea..97d45cc85 100644 --- a/docs/extending/testing.mdx +++ b/docs/extending/testing.mdx @@ -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 + @@ -113,3 +125,70 @@ TEST(MyFlipperPluginTests, testDummy) { + +## Running (Flipper) tests + +### Flipper Desktop + + + +Run `yarn jest` or `yarn jest --watch` in the `desktop` directory of your Flipper checkout. + + + + + +Run `yarn jest` or `yarn jest --watch` in `~/fbsource/xplat/sonar/desktop` + + + +### Flipper SDK + +#### Android (Java) + + + +##### Gradle: + +In the root directory of the checkout: + +``` +./gradlew android:test +``` + + + + + +##### 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` + + + + + +### 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. + + + +### React Native + +See [testing React Native](testing-rn). diff --git a/docs/tutorial/js-setup.mdx b/docs/tutorial/js-setup.mdx index 4cf16b968..10fe16188 100644 --- a/docs/tutorial/js-setup.mdx +++ b/docs/tutorial/js-setup.mdx @@ -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. diff --git a/website/sidebars.js b/website/sidebars.js index 74c512da1..ea2e1c4c9 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -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([