Written by Vijit Ail✏️
Real-time collaboration has become more critical in today's digital world. Whether for remote work, online gaming, or shared creative projects, interacting and collaborating in real time is a crucial feature of many modern applications.
In this article, we’ll explore PartyKit, a powerful SDK designed to simplify the development of real-time collaborative applications. We will also demonstrate how to use PartyKit to build a real-time code editor with collaborator functionality in React.
Jump ahead:
What is PartyKit?
PartyKit is an SDK designed for building real-time, collaborative applications leveraging WebSockets to make the process easier. It supports several popular collaboration frameworks like Y.js, automerge, and replicache, allowing developers to quickly and easily add real-time collaboration features to existing apps with minimal code.
PartyKit also enables developers to build multiplayer apps and add real-time experiences to existing projects without worrying about the operational complexity and cost of real-time infrastructure. Let’s take a look at some of its key features:
- Ease of use: Requires only minimal coding effort, using simple npm commands, to create new applications with server and client components
- Real-time collaboration: Facilitates real-time communication via WebSocket events, enabling sending, listening, and broadcasting messages to clients
- Edge computing: Leverages edge computing networks to intelligently route and optimize connections from users across the globe, supporting scalability without developer intervention
- Development language support: Supports modern JavaScript, TypeScript, npm modules, and WebAssembly modules
- Developer tools: Includes local development tools, deploy previews, and secret management, enabling seamless integration with development workflows and stacks
- Framework support: Supports popular collaboration frameworks like Y.js, automerge, and replicache, allowing quick addition of real-time collaboration features to existing apps
Building a multiplayer app with PartyKit
To demonstrate how to leverage PartyKit to create a multiplayer app, let’s build a real-time code editor with collaborator functionality using React and PartyKit.
Setting up PartyKit
To get started, install the required dependencies by running the following command:
> yarn add react react-dom partykit partysocket
> yarn add -D parcel @types/react @types/react-dom
Creating the server
The core elements of a PartyKit application consist of the server and the client. The server is a JavaScript module that exports an object; the object outlines the server's behavior, mainly responding to WebSocket events. The PartyKit client establishes a connection with this server and listens to the events.
Here’s the server-side code; it’s a simple script written in TypeScript:
import type { PartyKitServer } from "partykit/server";
export default {
async onConnect(ws, room) {
const codeEditorValue = (await room.storage.get(
"codeEditorValue"
)) as string;
if (codeEditorValue) ws.send(codeEditorValue);
},
onMessage(message, ws, room) {
room.storage.put("codeEditorValue", message);
room.broadcast(message as string, [ws.id]);
},
} satisfies PartyKitServer;
The above code imports the PartyKitServer
type from the partykit/server
module. Then it exports an object that satisfies the PartyKitServer
interface, meaning it contains the methods expected by PartyKit to handle server-side operations.
The exported object contains two methods:
-
onConnect(ws, room)
: This method is triggered whenever a new client (ws
) connects to aroom
. It retrieves the current value of the code editor from theroom
storage. If there is a value stored, it sends the value to the newly connected client. This ensures that the new client receives the current state of the code editor when they connect -
onMessage(message, ws, room)
: This method is triggered whenever a message is received from a client. It updates theroom
storage with the newcodeEditorValue
received in themessage
. Next, it broadcasts thismessage
to all clients connected to theroom
, except the client that sent themessage
Deploying the application
Now, let’s deploy the application to the cloud using the following command:
npx partykit deploy server/index.ts --name vijit-ail-demo
Be sure to take note of the production URL of the deployed code. You’ll need it later to establish a connection to the server from the frontend code.
Configuring the frontend
Next, let's proceed to configure the frontend. The following code snippets will facilitate the creation of a basic React application:
<!-- app/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>PartyKit App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="index.tsx"></script>
</body>
</html>
// app/index.tsx
import { createRoot } from "react-dom/client";
import React from "react";
import { App } from "./App";
const container = document.getElementById("app") as HTMLElement;
const root = createRoot(container);
root.render(<App />);
Run the following command to install the monaco-editor
and the uuid
package:
yarn add @monaco-editor/react monaco-editor uuid
The monaco-editor
is a robust and feature-rich code editor that powers VS Code. Its integration into our application will provide a sophisticated editing interface, enabling seamless code editing and collaboration.
The uuid
package is necessary for generating unique identifiers. These identifiers will be instrumental in distinguishing between different sessions in our collaborative code editor application.
Setting up the collaborative code editor
The following code sets up a simple real-time collaborative code editor using the PartySocket client API and Monaco Editor in a React app. When a user types in the editor, the value is sent to the server and broadcasted to all other connected clients, ensuring that all users see the same content in real time:
import PartySocket from "partysocket";
import React, { useEffect, useState } from "react";
import Editor from "@monaco-editor/react";
import * as uuid from "uuid";
let roomId = window.location.hash?.substring(1);
if (!roomId) {
roomId = uuid.v4();
window.location.hash = roomId;
}
const socket = new PartySocket({
host: "vijit-ail-demo.vijit-ail.partykit.dev",
room: roomId,
});
export function App() {
const [editorValue, setEditorValue] = useState("");
const handleChange = (value: string | undefined) => {
if (value === undefined) return;
socket.send(value);
};
const onIncomingMessage = (message: MessageEvent) => {
setEditorValue(message.data);
};
useEffect(() => {
socket.addEventListener("message", onIncomingMessage);
return () => socket.removeEventListener("message", onIncomingMessage);
}, []);
return (
<Editor
height="90vh"
defaultLanguage="javascript"
theme="vs-dark"
onChange={handleChange}
value={editorValue}
/>
);
}
In the above code, we extract the roomId
from the URL. If it doesn't exist, we generate a new roomId
using the uuid
package and update the URL.
Next, we create a new PartySocket
instance, specifying the host
and room
in its configuration. In the App
component, we define a piece of state editorValue
to hold the current value of the editor.
The handleChange
function sends the current value of the editor to the server whenever it changes. The onIncomingMessage
function updates the editorValue
state whenever a new message is received from the server.
In the useEffect
Hook, we set up an event listener for the message
event on the socket
. Finally, we render the Editor
component from @monaco-editor/react
, passing the necessary props including editorValue
, and the handleChange
function as the onChange
callback.
Here’s the final result of the code, a real-time collaboration between two users:
PartyKit vs. Socket.IO
Socket.IO has long been famous for enabling real-time bidirectional event-based communication in applications. It has served as a reliable library that uses WebSockets as a transport protocol with fallbacks on the HTTP long-polling in environments where WebSockets are not supported.
PartyKit, on the other hand, is a relatively new entrant but comes with a host of features that make it an attractive alternative. Here are some key distinctions between PartyKit and Socket.IO:
- Inbuilt collaboration framework support: One of the significant advantages of PartyKit is its inbuilt support for popular collaboration frameworks like Y.js, automerge, and replicache. This is particularly beneficial for developers working on applications that require real-time collaborative features, as it eliminates the need to manually integrate these frameworks, saving time and reducing complexity. Socket.IO does not offer this inbuilt support, requiring developers to manually incorporate any collaboration frameworks they wish to use
- Edge computing: PartyKit leverages the power of edge computing to optimize connections and support a global user base without manual developer intervention. This is a significant advantage for applications with globally dispersed users, as it ensures low latency and a seamless user experience, regardless of user location. In contrast, Socket.IO does not have inbuilt support for edge computing, and optimizing connections for a global user base would require additional manual setup and infrastructure
- Developer-friendly tools: PartyKit has a suite of developer-friendly tools, including local development tools, deploy previews, and secret management. These tools simplify the development process and integrate seamlessly with existing development workflows. Socket.IO, while offering a robust feature set, does not include these additional tools, which means developers may need to spend extra time setting up their development environment
- Simplified development process: PartyKit is designed to streamline the development process as much as possible. Creating a new application with server and client components requires minimal coding effort and can be achieved with simple npm commands. Socket.IO, while manageable, often requires more setup and a deeper understanding of its API and features
- Language support: PartyKit supports modern JavaScript, TypeScript, npm modules, and WebAssembly modules. This provides flexibility for developers and allows use of the tools and languages they are most comfortable with. Socket.IO primarily supports JavaScript, and while it can be used with TypeScript and other languages that compile to JavaScript, it does not have inbuilt support for WebAssembly modules
While Socket.IO remains a powerful and widely-used library for real-time applications, PartyKit offers several unique benefits that make it an attractive alternative, particularly for developers building real-time collaborative applications or those looking for inbuilt edge computing support and developer-friendly tools.
Conclusion
PartyKit is a powerful and user-friendly SDK that simplifies the development of real-time collaborative applications. This article demonstrated how to build a real-time code editor with collaborator functionality using React and PartyKit. We investigated the benefits and improvements that PartyKit offers over Socket.IO. With its ease of use, support for popular collaboration frameworks, and inbuilt developer tools, PartyKit is an excellent choice for developers looking to build real-time, collaborative applications.
Get set up with LogRocket's modern React error tracking in minutes:
- Visit https://logrocket.com/signup/ to get an app ID.
- Install LogRocket via NPM or script tag.
LogRocket.init()
must be called client-side, not server-side.
NPM:
$ npm i --save logrocket
// Code:
import LogRocket from 'logrocket';
LogRocket.init('app/id');
Script Tag:
Add to your HTML:
<script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script>
<script>window.LogRocket && window.LogRocket.init('app/id');</script>
3.(Optional) Install plugins for deeper integrations with your stack:
- Redux middleware
- ngrx middleware
- Vuex plugin
Top comments (0)