Collaborative Coding in Monaco Editor
Tags: monaco, react, firebase, firepad
Published: 2021-07-21 01:20:18

Code-Pair/Collaborative Coding is a trending topic in the landscape of remote-working/remote-hiring. In this post, We will discuss how we can build such a system on our own in less than 20 minutes.


## What is Code-Pairing?

![Code-Pairing](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/errrdu0lkb0bkaqu5nm7.png)

In Code-Pairing there are more than one users sharing the same code and editing it in real-time. Code-Pairing has lots of use-cases like helping a teammate, instructing interns/students, real time interviews etc. Possibilities are endless.

## System Architecture

Lets take a look how the system architecture of such simplified system might look.
![collaborative coding system archetecture](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ghzxqloqm0wgusdl1mor.png)

## Tech Stack

Today we will talk about how we can build such a system, using some of the most popular tools in the current tech world. We are going to build this project in ReactJs but keep in mind end product can be achieved through any framework.

We will be using [Monaco-Editor](https://microsoft.github.io/monaco-editor) as our code editor. If you don't already know, Monaco-Editor is the same Editor which powers [VSCode](https://code.visualstudio.com). Developed by Microsoft, is currently one of the most powerful opensource editor in market.

We will also be using Firebase's [Realtime Database](https://firebase.google.com/docs/database) as backend. 

We will be using an amazing library [@hackerrank/firepad](https://www.npmjs.com/package/@hackerrank/firepad), This library will automatically take care of managing editor-state in [Firebase](https://firebase.google.com) automatically for us. Not only that but it also automatically highlight the cursor of each user and where exactly other users are typing.

## Code it Out

Lets get started with the setup. 

### 1. Create a new React Project. 
```sh
npx create-react-app collaboratory
```

### 2. Install Dependencies
```sh
yarn add @hackerrank/firepad firebase@8.8.1 @monaco-editor/react monaco-editor 
```

### 3. Add Editor
Lets add editor by modifying our App.js and lets start the developement server by `npm start`.

```jsx
import Editor from "@monaco-editor/react";
import {useRef,useState} from 'react';


function App() {

  const editorRef = useRef(null);
  const [editorLoaded,setEditorLoaded] = useState(false);

  function handleEditorDidMount(editor, monaco) {
    editorRef.current = editor;
    setEditorLoaded(true);
  }

  return (
    <div>
      <Editor
       height="90vh"
       defaultLanguage="javascript"
       theme="vs-dark"
       defaultValue="// Welcome to My Editor"
       onMount={handleEditorDidMount}
     />
    </div>
  );
}

export default App;
```

### 4. Setup Firebase.
If you already have firebase set up skip to next step.
Go to [https://console.firebase.google.com/u/2/](https://console.firebase.google.com/u/0).

#### i. Create Firebase App
![Create Firebase App](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hwgu2ey97e71d5jqf2tk.jpg)

#### ii. Create Realtime Database
![Go to Realtime Database](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ufy9j5f52wo1gsn0u3uc.jpg)

#### iii. Select Region 'United States', 
Other regions can be choose as per your targeted region.
![Select Realtime Database Region](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yk76tnwhzybq2uxezacw.jpg)

#### iv. Select 'Start in Test Mode'
![Realtime Database Start in Test Mode](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s08wc9e8lo56cybe7d9l.jpg)

#### v. Go to Project Settings
![go to firebase project settings](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fy9ivr9g6xmgz4y67w90.jpg)

#### vi. Create an app.
Create an app from the bottom of General project settings.
![Create a Firebase app.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dyv9yg796bxmcrucg315.jpg)

#### vii. Register Firebase App Name
![Register Firebase App Name](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aiux6waykp6hg37iuh7v.jpg)

#### viii. Copy Firebase Configuration
Copy object next to firebaseConfig
![Copy Firebase Configuration](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ck5bl6yst8ll9ieo91d6.jpg)

### 5. Create a file `firebaseConfig.js` and Paste copied Firebase config.
Create `firebaseConfig.js` file in `src` folder.
```javascript

const firebaseConfig =  {
    apiKey: "#####################################", // important
    authDomain: "############.firebaseapp.com", // important
    databaseURL: "https://########.firebaseio.com", // important
    projectId: "###########",
    storageBucket: "#########.appspot.com",
    messagingSenderId: "############3",
    appId: "#############",
    measurementId: "G-########"
  };

export default firebaseConfig;

```

### 6. Initialize Firebase SDK
Import firebase sdk
```jsx
  import firebase from "firebase";
  import firebaseConfig from './firebaseConfig';
```
Inside App.js, We do a initialization of firebase sdk
```jsx
  useEffect(() => {
    if(!firebase.apps.length){
      // Make sure initialization happens only once
      firebase.initializeApp(firebaseConfig); 
    } 
    else{
      firebase.app();
    }
  }, []);

```

### 7. Instantiate Firepad
Import Firepad Monaco Adapter
```jsx
import {fromMonaco} from '@hackerrank/firepad';
```
We initialize firepad adapter for monaco
```jsx
useEffect(() => {
    if(!editorLoaded){
      // If editor is not loaded return
      return;
    }

    const dbRef = firebase.database().ref().child(`pair001`); // Can be anything in param, use unique string for unique code session
    
    const firepad = fromMonaco(dbRef,editorRef.current);

    const name = prompt("Enter your Name :"); // Name to highlight who is editing where in the code
    if(name){
        firepad.setUserName(name);
    }
  
  },[editorLoaded]);
```



That's It. We should be good to go. Open project [localhost:3000](http://localhost:3000) in two separate tabs/window and start typing in one. Other should update as well.

Final Code should look like the following.
```jsx
import React {useRef,useEffect,useState} from 'react';

import Editor from "@monaco-editor/react";

import firebaseConfig from './firebaseConfig';

import firebase from "firebase";
import {fromMonaco} from '@hackerrank/firepad';

function App() {

  const editorRef = useRef(null);
  const [editorLoaded, setEditorLoaded] = useState(false);

  function handleEditorDidMount(editor, monaco) {
    editorRef.current = editor; 
    setEditorLoaded(true);
  }

  useEffect(() => {
    if(!firebase.app.length){
      firebase.initializeApp(firebaseConfig);
    } 
    else{
      firebase.app();
    }
  }, []);

  useEffect(() => {
    if(!editorLoaded){
      return;
    }

    const dbRef = firebase.database().ref().child(`pair001`);
    
    const firepad = fromMonaco(dbRef,editorRef.current);
    const name = prompt("Enter your Name :");
    firepad.setUserName(name);
  

  },[editorLoaded]);

  return (
    <div>
      <Editor
       height="90vh"
       defaultLanguage="javascript"
       theme="vs-dark"
       defaultValue="// Welcome to My Editor"
       onMount={handleEditorDidMount}
     />
    </div>
  );
}

export default App;

```

## Thank You have a nice day

#### About me

My name is Shubham Shekhar, I am a Software Developer, I have experience in ReactJs, Redux, NextJs, Material Ui, Bootstrap, Testing-Library, Jest,  NodeJs, etc. I am highly focused towards learning new things and improving my way up. Feel free to contact me. 

Github : [https://github.com/Shubham567](https://github.com/Shubham567)
Contact Me: shubhamshekhar567@gmail.com