Skip to main content

Building a JavaScript (browser) Plugin

This tutorial requires a browser that supports WebSockets.

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

Do not start Flipper client in production! Preferably, do not even include Flipper in your production builds!

// We want to import and start flipper client only in development and test modes
let flipperClientPromise: Promise<FlipperClient> | undefined;
if (process.env.NODE_ENV !== 'production') {
flipperClientPromise = import('js-flipper').then(({flipperClient}) => {
flipperClient.start('React Tic-Tac-Toe');
return flipperClient;
});
}

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:

export interface FlipperPlugin {
/**
* @return The id of this plugin. This is the namespace which Flipper desktop plugins will call
* methods on to route them to your plugin. This should match the id specified in your React
* plugin.
*/
getId(): string;

/**
* Called when a connection has been established. The connection passed to this method is valid
* until {@link FlipperPlugin#onDisconnect()} is called.
*/
onConnect(connection: FlipperPluginConnection): void;

/**
* Called when the connection passed to `FlipperPlugin#onConnect(FlipperConnection)` is no
* longer valid. Do not try to use the connection in or after this method has been called.
*/
onDisconnect(): void;

/**
* Returns true if the plugin is meant to be run in background too, otherwise it returns false.
*/
runInBackground?(): boolean;
}

These onConnect and onDisconnect events are triggered every time the plugin becomes (in)active in the Flipper desktop application. If the plugin is a background plugin, 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:

// TicTacToe game status
const [status, setStatus] = useState('Waiting for Flipper Desktop Player...');
// TicTacToe game state
const [gameState, setGameState] = useState<GameState>({
cells: [],
turn: ' ',
winner: ' ',
});
// Flipper connection instance
const [connection, setConnection] = useState<FlipperPluginConnection>();

useEffect(() => {
flipperClientPromise?.then(flipperClient => {
flipperClient.addPlugin({
getId() {
// Name of the plugin
return 'ReactNativeTicTacToe';
},
onConnect(connection) {
// Once we connected, we display it to the user
setStatus('Desktop player present');
// And stash the connection object
setConnection(connection);

// We start listening to updates from Flipper Desktop
connection.receive('SetState', (gameState: GameState) => {
if (gameState.winner !== ' ') {
setStatus(
`Winner is ${gameState.winner}! Waiting for a new game...`,
);
} else {
setStatus(
gameState.turn === 'X'
? 'Your turn...'
: 'Awaiting desktop players turn...',
);
}
setGameState(gameState);
});

// We also request the initial state of the game from Flipper Desktop
connection.send('GetState');
},
onDisconnect() {
// When Flipper Desktop disconnects, we show it to the user
setConnection(undefined);
setStatus('Desktop player gone...');
},
});
});
}, []);

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 Client Plugin API 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):