Add documentation

Summary: Document Flipper integration with JavaScript clients.

Reviewed By: passy

Differential Revision: D31827187

fbshipit-source-id: c40d8820241c0f85bd2366a0c087d4270d316c71
This commit is contained in:
Andrey Goncharov
2021-10-22 06:27:44 -07:00
committed by Facebook GitHub Bot
parent 02115722b3
commit 9b16d0c29a
8 changed files with 335 additions and 49 deletions

View File

@@ -15,7 +15,7 @@ To build a client plugin, implement the `FlipperPlugin` interface.
The ID that is returned from your implementation needs to match the `name` defined in your JavaScript counterpart's `package.json`.
<Tabs defaultValue="android" values={[{label: 'Android', value: 'android'}, { label: 'iOS', value: 'ios'}, { label: 'C++', value: 'cpp'}, { label: 'React Native (JS)', value: 'rn' }]}>
<Tabs defaultValue="android" values={[{label: 'Android', value: 'android'}, { label: 'iOS', value: 'ios'}, { label: 'C++', value: 'cpp'}, { label: 'React Native (JS)', value: 'rn' }, { label: 'React (JS)', value: 'js' }]}>
<TabItem value="android">
```java
@@ -91,15 +91,54 @@ addPlugin({
return 'MyFlipperPlugin';
},
onConnect(connection) {
console.log("connected");
console.log('connected');
},
onDisconnect() {
console.log("disconnected");
console.log('disconnected');
},
runInBackground() {
return false;
}
})
},
});
```
</TabItem>
<TabItem value="js">
<div class="warning">
Please note that using Flipper from JavaScript in your browser requires the package [`js-flipper`](https://www.npmjs.com/package/js-flipper) to be installed in the hosting application.
</div>
```javascript
import {flipperClient} from 'js-flipper';
// We want to import and start flipper client only in development and test modes
// We want to exclude it from our production build
let flipperClientPromise;
if (process.env.NODE_ENV !== 'production') {
flipperClientPromise = import('js-flipper').then(({flipperClient}) => {
flipperClient.start('React Tic-Tac-Toe');
return flipperClient;
});
}
flipperClientPromise?.then((flipperClient) => {
flipperClient.addPlugin({
getId() {
return 'MyFlipperPlugin';
},
onConnect(connection) {
console.log('connected');
},
onDisconnect() {
console.log('disconnected');
},
runInBackground() {
return false;
},
});
});
```
</TabItem>
</Tabs>
@@ -109,7 +148,7 @@ addPlugin({
`onConnect` will be called when your plugin becomes active. This will provide a `FlipperConnection` allowing you to register receivers for desktop method calls and respond with data.
<Tabs defaultValue="android" values={[{label: 'Android', value: 'android'}, { label: 'iOS', value: 'ios'}, { label: 'C++', value: 'cpp'}, { label: 'React Native (JS)', value: 'rn' }]}>
<Tabs defaultValue="android" values={[{label: 'Android', value: 'android'}, { label: 'iOS', value: 'ios'}, { label: 'C++', value: 'cpp'}, { label: 'React Native (JS)', value: 'rn' }, { label: 'React (JS)', value: 'js' }]}>
<TabItem value="android">
```java
@@ -171,17 +210,61 @@ addPlugin({
return 'MyFlipperPlugin';
},
onConnect(connection) {
console.log("connected");
connection.receive("getData", (data, responder) => {
console.log("incoming data", data);
console.log('connected');
connection.receive('getData', (data, responder) => {
console.log('incoming data', data);
// respond with some data
responder.success({
ack: true
ack: true,
});
});
},
// ...as-is
})
});
```
</TabItem>
<TabItem value="js">
```javascript
flipperClient.addPlugin({
getId() {
return 'MyFlipperPlugin';
},
onConnect(connection) {
console.log('connected');
connection.receive('getData', (data) => {
console.log('incoming data', data);
// return data to send it as a response
return {
ack: true,
};
});
// Flipper client can also send the data you return from your async functions
connection.receive('getDataAsync', async (data) => {
console.log('incoming data', data);
const myAsyncData = await doAsyncStuff();
// return data to send it as a response
return {
data: myAsyncData,
};
});
// Flipper client catches your exceptions and sends them as an error response to the desktop
connection.receive('getErrorData', (data) => {
console.log('incoming data', data);
throw new Error('Ooops');
});
// It catches the execptions in your async functions as well
connection.receive('getErrorDataAsync', async (data) => {
console.log('incoming data', data);
const myAsyncData = await doAsyncStuff();
if (!myAsyncData) {
throw new Error('Ooops! Async data is not there!!!');
}
});
},
// ...as-is
});
```
</TabItem>
@@ -191,7 +274,7 @@ addPlugin({
You don't have to wait for the desktop to request data though, you can also push data directly to the desktop. If the JS plugin subscribes to the same method, it will receive the data.
<Tabs defaultValue="android" values={[{label: 'Android', value: 'android'}, { label: 'iOS', value: 'ios'}, { label: 'C++', value: 'cpp'}, { label: 'React Native (JS)', value: 'rn' }]}>
<Tabs defaultValue="android" values={[{label: 'Android', value: 'android'}, { label: 'iOS', value: 'ios'}, { label: 'C++', value: 'cpp'}, { label: 'React Native (JS)', value: 'rn' }, { label: 'React (JS)', value: 'js' }]}>
<TabItem value="android">
```java
@@ -227,11 +310,27 @@ addPlugin({
return 'MyFlipperPlugin';
},
onConnect(connection) {
console.log("connected");
connection.send("newRow", { message: "Hello" });
console.log('connected');
connection.send('newRow', {message: 'Hello'});
},
// ...as-is
})
});
```
</TabItem>
<TabItem value="js">
```javascript
flipperClient.addPlugin({
getId() {
return 'MyFlipperPlugin';
},
onConnect(connection) {
console.log('connected');
connection.send('newRow', {message: 'Hello'});
},
// ...as-is
});
```
</TabItem>
@@ -299,10 +398,16 @@ Here, `sendData` is an example of a method that might be implemented by the Flip
### Bi-directional communication demo
An minimal communication demo can be found in our [Sample project]:
An minimal communication demo for Android and iOS can be found in our Sample project:
* [Desktop implementation](https://github.com/facebook/flipper/blob/main/desktop/plugins/public/example/index.tsx)
* [Android implementation](https://github.com/facebook/flipper/blob/main/android/sample/src/debug/java/com/facebook/flipper/plugins/example/ExampleFlipperPlugin.java) / [iOS implementation](https://github.com/facebook/flipper/tree/7bd4f80c2570bebb52af3cf49e45fc6130d6a473/iOS/Plugins/FlipperKitExamplePlugin/FlipperKitExamplePlugin)
* [Android](https://github.com/facebook/flipper/blob/main/android/sample/src/debug/java/com/facebook/flipper/plugins/example/ExampleFlipperPlugin.java) / [iOS](https://github.com/facebook/flipper/tree/7bd4f80c2570bebb52af3cf49e45fc6130d6a473/iOS/Plugins/FlipperKitExamplePlugin/FlipperKitExamplePlugin)
For React Native and JavaScript we have a simple game of Tic Tac Toe:
* [Desktop implementation](https://github.com/facebook/flipper/blob/main/desktop/plugins/public/rn-tic-tac-toe/index.tsx)
* [React Native implementation](https://github.com/facebook/flipper/tree/main/react-native/ReactNativeFlipperExample) / [JavaScript (React) implementation](https://github.com/facebook/flipper/tree/main/js/react-flipper-example)
## Background Plugins

View File

@@ -6,12 +6,13 @@ import useBaseUrl from '@docusaurus/useBaseUrl';
import FbInstallation from './fb/installation.mdx';
Flipper helps you debug Android and iOS apps running in an emulator/simulator or connected physical development devices. Flipper consists of two parts:
Flipper helps you debug Android, iOS, and even web apps running in an emulator/simulator, connected physical development devices, or in your browser. Flipper consists of two parts:
- The desktop app
- The native mobile SDKs for Android and iOS
- The native mobile SDKs for Android and iOS, the client for JavaScript, or even a third-party client you could implement yourself or find on the web
Once you start Flipper and launch an emulator/simulator or connect a device, you'll start to see the device logs (and any other device-level plugins that work with your device).
For web apps, we do not ship any built in plugins yet.
To see app specific data, you need to integrate the Flipper SDK into your app. See the relevant section in the sidebar for how to do that.
@@ -21,9 +22,10 @@ To see app specific data, you need to integrate the Flipper SDK into your app. S
The desktop part of Flipper doesn't need any particular setup. Simply download the latest build for [Mac](https://www.facebook.com/fbflipper/public/mac), [Linux](https://www.facebook.com/fbflipper/public/linux) or [Windows](https://www.facebook.com/fbflipper/public/windows) and launch it. If you're on macOS, you can run `brew install --cask flipper` to let `homebrew` manage installation and upgrades (simply run `brew upgrade` to upgrade when a new version is released, although it might take a few hours up to a day for the package to be upgraded on `homebrew`).
In order to work properly, Flipper requires a working installation of the Android and (if where applicable) iOS development tools on your system, as well as the [OpenSSL](https://www.openssl.org) binary on your `$PATH`.
To work properly with mobile apps, Flipper requires a working installation of the Android and (if where applicable) iOS development tools on your system, as well as the [OpenSSL](https://www.openssl.org) binary on your `$PATH`. A compatible OpenSSL for Windows can be downloaded [here](https://slproweb.com/products/Win32OpenSSL.html) or from Chocolatey with `choco install openssl`.
If you are hacking a JS app, you should be good to go without any extra dependencies installed.
A compatible OpenSSL for Windows can be downloaded [here](https://slproweb.com/products/Win32OpenSSL.html) or from Chocolatey with `choco install openssl`.
</OssOnly>
<FbInternalOnly>

View File

@@ -0,0 +1,83 @@
---
id: javascript
title: Set up your JavaScript App
sidebar_label: JavaScript (browser / Node.js)
---
import useBaseUrl from '@docusaurus/useBaseUrl';
import Link from '@docusaurus/Link';
To set up Flipper in your JavaScript app, you need to add the neccessary dependencies to your
app, initialize the Flipper client and enable the plugins you want to use.
Currently, we do not ship any plugins for JavaScript environments you can use right away, but we encourage you to <Link to={useBaseUrl("/docs/extending/create-plugin")}>write your own</Link>!
## Dependencies
Flipper JavaScript SDK is distiributed via NPM. To add it to your app run:
```sh
npm install js-flipper
```
or
```sh
yarn add js-flipper
```
## Application Setup
Flipper SDK works in browser and Node.js environments. For browsers, it works out-of-the-box as long as your browser supports [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket). For node.js, it requires a compatible WebSocket implementation (e.g. [ws](https://github.com/websockets/ws)).
You MUST NOT start Flipper client in production. In browser environments, you should think about not including it in the final production build at all.
Here is how you setup Flipper in your browser:
```ts
import flipperClient from 'js-flipper';
// Start the client and pass your app name
flipperClient.start('My cool browser app');
```
Here is how you can do it in your Node.js app:
```ts
import flipperClient from 'js-flipper';
// Say, you decided to go with 'ws' as your WebSocket implementation
// https://github.com/websockets/ws
import WebSocket from 'ws';
// Start the client and pass your app name
// You might ask yourself why there is the second argument `{ origin: 'localhost:' }`
// Flipper Desktop verifies the `Origin` header for every WS connection. You need to set it to one of the whitelisted values (see `VALID_WEB_SOCKET_REQUEST_ORIGIN_PREFIXES`).
flipperClient.start('My cool nodejs app', { websocketFactory: url => new WebSocket(url, {origin: 'localhost:'}) });
```
As you can see, `flipperClient` accepts an options object as a second parameter to its `start` method. Here is what you can pass there:
```ts
interface FlipperClientOptions {
// Make the client connect to a different URL
urlBase?: string;
// Override WebSocket implementation (Node.js folks, it is for you!)
websocketFactory?: (url: string) => FlipperWebSocket;
// Override how errors are handled (it is simple `console.error` by default)
onError?: (e: unknown) => void;
// Timeout after which client tries to reconnect to Flipper
reconnectTimeout?: number;
}
```
## Enabling plugins
Flipper is just a communication channel between the desktop app and your application. Its true power comes from its plugins.
All plugins must be added to the client. Client communicates the list of available plugins to the desktop upon connection.
You can add a plugin by calling:
```ts
flipperClient.addPlugin(/* your plugin */)
```
Chekc out <Link to={useBaseUrl("/docs/extending/create-plugin")}>documentation on creating plugins</Link> to write your own!

View File

@@ -0,0 +1,49 @@
---
id: javascript
title: Building a JavaScript (browser) Plugin
---
import useBaseUrl from '@docusaurus/useBaseUrl';
import Link from '@docusaurus/Link';
This tutorial requires a browser that supports [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket).
## Step 1. Install Flipper JavaScript SDK
Add Flipper client to your web application. Run `npm install js-flipper` (`yarn add js-flipper`)
## Step 2. Start Flipper client
<div class="warning">
Do not start Flipper client in production! Preferably, do not even include Flipper in your production builds!
</div>
```tsx file=js/react-flipper-example/src/FlipperTicTacToe.tsx start=DOCS_START_CLIENT_START end=DOCS_START_CLIENT_END
```
## Step 3. Call `addPlugin` to add your plugin
To register a new plugin with Flipper call `flipperClient.addPlugin` and pass your plugin as an object. Your plugin must conform to the following interface:
```ts file=js/js-flipper/src/plugin.ts start=DOCS_FLIPPER_PLUGIN_START end=DOCS_FLIPPER_PLUGIN_END
```
These `onConnect` and `onDisconnect` events are triggered every time the plugin becomes (in)active in the Flipper desktop application.
If the plugin is a <Link to={useBaseUrl("/docs/extending/create-plugin#background-plugins")}>background plugin</Link>, these events are triggered typically only once (they might be triggered never, if the Desktop user didn't enable the plugin, or multiple times if they enabled or disabled the plugin a few times).
The `onConnect` callback receive a `connection` which can be used to communicate with the backend:
```tsx file=js/react-flipper-example/src/FlipperTicTacToe.tsx start=DOCS_ADD_PLUGIN_START end=DOCS_ADD_PLUGIN_END
```
You might want to store the connection somewhere to be able to send more events as long as `onDisconnect` event hasn't been fired.
The `connection` object can also be used to listen to messages coming from the Desktop plugin. See <Link to={useBaseUrl("/docs/extending/create-plugin")}>Client Plugin API</Link> for details.
## Live demo
An example plugin to play a little Tic-Tac-Toe between the Flipper Desktop and a React app can be found inside this repository as well (run `yarn && yarn start` in `js/react-flipper-example` to start the test project):
* The React plugin implementation: [FlipperTicTacToe.tsx](https://github.com/facebook/flipper/tree/main/js/react-flipper-example/src/FlipperTicTacToe.tsx)
* The Flipper Desktop plugin implementation: [rn-tic-tac-toe/index.tsx](https://github.com/facebook/flipper/blob/main/desktop/plugins/public/rn-tic-tac-toe/index.tsx)