drah allows you to write functions that are run in another environment with minimal setup.
From a development side, it means you can execute a function that is written in another environment. It's also got great typescript support.
This example shows setting a server and client to allow the ui to use functions in the main.
In practice we have an additional server and client which allows the main to use functions in the ui, it's much the same, but with the figma message apis switched.
// file in main
function getCurrentPageName() {
const name = figma.currentPage.name;
return name;
}
export const mainDrahServer = new DrahServer({
handlers: {
getCurrentPageName,
},
sendToClient: (message: string) => {
figma.ui.postMessage({
type: 'from-main-drah-server',
data: message,
});
},
});
export type MainDrahServerActions = ExtractActionsFromServer<typeof mainDrahServer>;
figma.ui.onmessage = async function handleMessage(pluginMessage) {
if (pluginMessage.type === 'from-main-drah-client') {
mainDrahServer.receiveFromClient(pluginMessage.data);
}
};
// file in ui
import type { MainDrahServerActions } from ' ..path to main drah server.. '
export const mainDrahClient = getRichDrahClient<MainDrahServerActions>({
sendToServer: (serializedData) => window.parent.postMessage({ pluginMessage: { type: 'from-main-drah-client', data: serializedData } }, '*'),
});
window.onmessage = async (event: MessageEvent<any>) => {
if (event.data.pluginMessage.type === 'from-main-drah-server') {
mainDrahClient.receiveFromServer(event.data.pluginMessage.data);
}
};
// any file in ui
async function demo() {
const currentPageName = await mainDrahClient.getCurrentPageName();
}
- drah-client: package which provides the mechanism to run functions on the server.
- drah-server: package which runs functions on the server in response to client calls.
To setup a new action service, you need to do some setup on both the processor and client
The server environment requires:
-
A
DrahServer
setup with:- handlers for actions you want to provide to clients (via constructor option
handlers
) - a mechanism to send responses back to the client (via constructor option
sendToClient
)
- handlers for actions you want to provide to clients (via constructor option
-
The
DrahServer
configured to receive requests from the client (via class methodreceiveFromClient
)
note: this example contains the following two placeholder functions that you need to implement.
- sendMessageToClient: function which sends messsages to the client environment
- onMessagefromClient: subscription which fires it's callback on messages from a client environment
import { DrahServer } from 'drah-server';
const drahServer = new DrahServer({
handlers: {
// While the functions here can be sync or async,
// in the client the corresponding function will
// always be async.
getAnswer: (options: { answerFor: string }) => 42,
},
sendToClient: (message: string) => sendMessageToClient(serializedData),
});
onMessagefromClient(function (message: string) => drahServer.receiveFromClient(message));
The client environment requires:
-
A
DrahClient
setup with:- a mechanism to send actions to the processor (via constructor option
sendToServer
)
- a mechanism to send actions to the processor (via constructor option
-
The
DrahClient
configured to receive responses from the processor (via class methodreceiveFromServer
)
note: this example contains the following two placeholder functions that you need to implement.
- sendMessageToServer: function which sends messsages to the server environment
- onMessagefromServer: subscription which fires it's callback on messages from a server environment
import { DrahClient } from 'drah-client';
const drahClient = new DrahClient<ActionProcessorHandlers>({
sendToServer: (serializedData) => sendMessageToServer(serializedData),
});
onMessagefromServer((message: string) => drahClient.receiveFromServer(event.data));
const answer = await drahClient.process('getAnswer', {
answerFor: 'Ultimate Question of Life, the Universe, and Everything',
});
// answer will be 42
The getRichDrahClient returns a DrahClient instance with a proxy setup to allow calling handlers directly on the drahClient.
note: this example contains the following two placeholder functions that you need to implement.
- sendMessageToServer: function which sends messsages to the server environment
- onMessagefromServer: subscription which fires it's callback on messages from a server environment
import { DrahClient } from 'drah-client';
const drahClient = new DrahClient<ActionProcessorHandlers>({
sendToServer: (serializedData) => sendMessageToServer(serializedData),
});
onMessagefromServer((message: string) => drahClient.receiveFromServer(event.data));
const answer = await drahClient.getAnswer({
answerFor: 'Ultimate Question of Life, the Universe, and Everything',
});
// answer will be 42