Walkthrough: Vite
See this example on GitHub, where you can find the instructions to run it yourself.
Check out the standalone
example first to understand the basics,
if you are not already familiar with Vite and React. Otherwise
you might get lost pretty fast!
Setup
The standalone example shows a scenario where the app calls the worker through workex. In this example, let's go a step further. The app will call the worker, and the worker needs to call back to the app to get some data.
This pattern is very useful if there are some very large data that doesn't make sense to send to the worker. Instead, it is required that the worker should compute what it needs, then asks for it.
Workex Setup
Similar to the standalone example, let's define the messaging interfaces first
// src/msg/proto.ts
import { WorkexPromise as Promise } from "./workex";
/**
* Functions the app can call on the worker
*
* @workex:send app
* @workex:recv worker
*/
export interface GreetWorker {
/** Ask the app for a name and greet the person! */
greet(): Promise<string>;
}
/**
* Functions the worker can call back to the app to get something
*
* @workex:send worker
* @workex:recv app
*/
export interface GreetApp {
/** Get the name of the person to greet */
getName(): Promise<string>;
}
Now run workex to generate the interfaces and workex library
workex --protocol greet src/msg/proto.ts
Run inside the examples/vite
directory.
If you don't have workex
installed yet, run npm run workex
instead.
The Worker Side
See the comments in the code that walks through the implementation
// src/worker.ts
import { WorkexPromise } from "./msg/workex";
import { GreetAppClient, bindGreetWorkerHost } from "./msg/sides/worker.ts";
import type { GreetWorker } from "./msg/proto.ts";
const options = { worker: self };
// Create the client used to call back to the app
const client = new GreetAppClient(options);
// Create the handler to handle the messages sent by app
// Note that the standalone case we used Delegate,
// here we are showing how to implement the host directly
class Handler implements GreetWorker {
async greet(): WorkexPromise<string> {
// get the person's name from the app
const name = await client.getName();
// handle potential communication errors
if (name.err) {
return name;
}
// greet the person
const greeting = `Hello, ${name.val}!`;
// return it back to the app
return { val: greeting };
}
}
// similar to the standalone example, we will let the worker
// initiate the handshake
const handshake = bindGreetWorkerHost(new Handler(), options);
handshake.initiate();
The App Side
In the React app, we will make a button that will call the worker when clicked.
// src/App.tsx
import { useState } from 'react'
import './App.css'
// Use the vite ?worker syntax to import the module as a worker directly!
import GreetWorker from './worker.ts?worker'
import { GreetWorkerClient, bindGreetAppHost } from './msg/sides/app.ts'
import { GreetApp } from './msg/proto';
import { hostFromDelegate, type Delegate } from './msg/workex';
async function createWorker(): Promise<GreetWorkerClient> {
// just some example data
const names = ["Alice", "Bob", "Charlie", "David", "Eve"];
const randomName = () => names[Math.floor(Math.random() * names.length)];
// note this setup is very similar to what we are doing in the worker
const worker = new GreetWorker();
const client = new GreetWorkerClient({ worker });
// here we use a delegate to bind the handler
const handler = {
async getName(): Promise<string> {
return randomName();
}
} satisfies Delegate<GreetApp>;
const handshake = bindGreetAppHost(hostFromDelegate(handler), { worker });
// note the worker side calls initiate() and the app side
// calls established()
await handshake.established();
return client;
}
// make sure you are handling the worker lifecycle correctly
// so you don't have resource leaks, especially if you need
// to terminate() the worker
//
// here we are just using a simple global variable
const greetClient = createWorker();
function App() {
const [message, setMessage] = useState("Press the button to greet someone!");
return (
<>
<h1>Workex Example with Vite</h1>
<div className="card">
<button onClick={async () => {
const client = await greetClient;
const message = await client.greet();
if (message.val) {
setMessage(message.val);
return
}
console.error(message.err);
}}>
Greet
</button>
<p>
{message}
</p>
</div>
</>
)
}
export default App
Run the Example
npm run dev