Build a real-time, collaborative code editor with PartyKit
Tags: react, webdev
Published: 2023-10-24 15:43:20

**Written by [Vijit Ail](https://blog.logrocket.com/author/vijitail/)✏️**

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?](#what-is-partykit)
*   [Building a multiplayer app with PartyKit](#building-multiplayer-app-partykit)
    *   [Setting up PartyKit](#setting-up-partykit)
    *   [Creating the server](#creating-the-server)
    *   [Deploying the application](#deploying-the-application)
    *   [Configuring the frontend](#configuring-the-frontend)
    *   [Setting up the collaborative code editor](#setting-up-collaborative-code-editor)
*   [PartyKit vs. Socket.IO](#partykit-vs-socket-io)

## 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 <a name="building-multiplayer-app-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 <a name="setting-up-partykit">

To get started, install the required dependencies by running the following command:

```bash
> 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:

```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 a `room`. It retrieves the current value of the code editor from the `room` 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 the `room` storage with the new `codeEditorValue` received in the `message`. Next, it broadcasts this `message` to all clients connected to the `room`, except the client that sent the `message`

### Deploying the application

Now, let’s deploy the application to the cloud using the following command:

```bash
npx partykit deploy server/index.ts --name vijit-ail-demo
```

![Deploying PartyKit Application](https://blog.logrocket.com/wp-content/uploads/2023/10/deploying-partykit-application.png) 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:

```html
<!-- 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>
```

```typescript
// 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:

```bash
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 <a name="setting-up-collaborative-code-editor">

The following code sets up a simple real-time collaborative code editor using the [PartySocket client API](https://docs.partykit.io/reference/partysocket-api/) and [Monaco Editor in a React app](https://blog.logrocket.com/build-web-editor-with-react-monaco-editor/). 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:

```typescript
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: ![Real-Time Code Editor Built PartyKit](https://blog.logrocket.com/wp-content/uploads/2023/10/real-time-code-editor-built-partykit.gif)

## PartyKit vs. Socket.IO <a name="partykit-vs-socket-io">

[Socket.IO](https://blog.logrocket.com/real-time-data-transfer-with-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:

1. Visit https://logrocket.com/signup/ to get an app ID.
2. Install LogRocket via NPM or script tag. `LogRocket.init()` must be called client-side, not server-side.

NPM:
```bash
$ npm i --save logrocket 

// Code:

import LogRocket from 'logrocket'; 
LogRocket.init('app/id');
```
Script Tag:
```javascript
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

[Get started now](https://lp.logrocket.com/blg/signup)