[]
        
(Showing Draft Content)

Tutorial: Deploying Collaboration Client and Server Separately

The SpreadJS Collaboration system enables real-time, multi-user editing experiences using the Collaboration Client (frontend) and Collaboration Server (backend).

This manual describes how to deploy these components independently, allowing full separation between the frontend (static website) and backend (Node.js WebSocket service).

Prerequisites

Key Features

  • Frontend–backend separation for flexible deployment.

  • Real-time synchronization of SpreadJS workbooks across multiple users.

  • Scalable backend built on Node.js and WebSocket.

  • SQLite-based storage for document state persistence.

  • Customizable frontend hosting (Nginx, Apache, IIS, etc.).

Project Structure

The project consists of two separate directories:

collaboration-server/   # Backend only – deploy to Node.js environment
│── server.js
│── init-database.js
│── package.json

collaboration-client/   # Frontend only – static site
│── public/
│   ├── index.html
│   ├── client.js
│   └── client.bundle.js  # generated by webpack build
│── webpack.config.js
│── package.json

Specific Step


Collaboration Server Setup

Step 1: Create the Project Directory

mkdir collaboration-server && cd collaboration-server
npm init -y

Step 2: Configure package.json

{
  "name": "collaboration-server",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "start": "node ./server.js"
  },
  "dependencies": {}
}

Step 3: Install Dependencies

npm install @mescius/js-collaboration @mescius/js-collaboration-ot
npm install @mescius/spread-sheets-collaboration
npm install sqlite3 @mescius/js-collaboration-ot-sqlite

Step 4: Create server.js

import http from 'http';
import sqlite3 from 'sqlite3';
import { Server } from '@mescius/js-collaboration';
import * as OT from '@mescius/js-collaboration-ot';
import { type } from '@mescius/spread-sheets-collaboration';
import { SqliteDb } from '@mescius/js-collaboration-ot-sqlite';

// Register the SpreadJS collaboration type
OT.TypesManager.register(type);

const httpServer = http.createServer();
const server = new Server({ httpServer });
const port = 8080;

// Initialize SQLite database and adapter
const db = new sqlite3.Database("./docs.db");
const sqliteDbAdapter = new SqliteDb(db);

// Configure OT document services
const documentServices = new OT.DocumentServices({ db: sqliteDbAdapter });
server.useFeature(OT.documentFeature(documentServices));

// Start the server
httpServer.listen(port, () => {
    console.log(`Collaboration server listening on port ${port}`);
});

Step 5: Initialize the Database

Create init-database.js:

import sqlite3 from "sqlite3";
const db = new sqlite3.Database("./docs.db");
async function initSqliteDataTables(db) {
    const run = (sql) => {
        return new Promise((resolve, reject) => {
            db.run(sql, (e) => (e ? reject(e) : resolve()));
        });
    };
    await run(
        `CREATE TABLE IF NOT EXISTS documents (
            id TEXT PRIMARY KEY,
            type TEXT NOT NULL,
            version INTEGER NOT NULL,
            snapshot_version INTEGER NOT NULL
        )`
    );
    await run(
        `CREATE TABLE IF NOT EXISTS operations (
            doc_id TEXT NOT NULL,
            version INTEGER NOT NULL,
            operation TEXT NOT NULL,
            PRIMARY KEY (doc_id, version),
            FOREIGN KEY (doc_id) REFERENCES documents (id) ON DELETE CASCADE
        )`
    );
    await run(
        `CREATE TABLE IF NOT EXISTS snapshot_fragments (
            doc_id TEXT NOT NULL,
            fragment_id TEXT NOT NULL,
            data TEXT NOT NULL,
            PRIMARY KEY (doc_id, fragment_id),
            FOREIGN KEY (doc_id) REFERENCES documents (id) ON DELETE CASCADE
        )`
    );
}
// Call the initialization function
initSqliteDataTables(db);

Run this step only on the first setup or when resetting the database.

node init-database.js

Collaboration Client Setup

Step 1: Create the Frontend Project

mkdir collaboration-client && cd collaboration-client
npm init -y

Step 2: Configure package.json

{
  "name": "collaboration-client",
  "version": "1.0.0",
  "scripts": {
    "build": "webpack"
  },
  "dependencies": {}
}

Step 3: Install Dependencies

# SpreadJS & collaboration client packages
npm install @mescius/spread-sheets @mescius/spread-sheets-collaboration-addon
npm install @mescius/js-collaboration-client @mescius/js-collaboration-ot-client
npm install @mescius/spread-sheets-collaboration-client

# Build tools
npm install --save-dev webpack webpack-cli style-loader css-loader

Step 4: Create the public Folder and Files

Create and update the front-end HTML page: public/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SpreadJS Real-Time Collaboration</title>
    <script src="./client.bundle.js"></script>
</head>
<body>
    <div id="ss" style="width:100vw; height:95vh; border:1px solid darkgray;"></div>
</body>
</html>

Create and update the front-end JavaScript code: public/client.js

import * as GC from '@mescius/spread-sheets';
import '@mescius/spread-sheets-collaboration-addon';
import { Client } from "@mescius/js-collaboration-client";
import * as OT from "@mescius/js-collaboration-ot-client";
import { type, bind } from '@mescius/spread-sheets-collaboration-client';
import "@mescius/spread-sheets/styles/gc.spread.sheets.excel2013white.css";

// Register the SpreadJS collaboration data type
OT.TypesManager.register(type);

// ===== IMPORTANT: Update this to your actual collaboration server address =====
// Example for local development:
const SERVER_URL = "ws://127.0.0.1:8080";

// Example for production:
// const SERVER_URL = "wss://collab.yourdomain.com";
// const SERVER_URL = "wss://your-app.herokuapp.com";

window.onload = async function () {
    // Initialize the SpreadJS workbook
    const workbook = new GC.Spread.Sheets.Workbook('ss');

    // Establish a client connection and join a collaboration room
    const conn = new Client(SERVER_URL).connect('room1');
    const doc = new OT.SharedDoc(conn);

    // Handle connection and document synchronization errors
    doc.on('error', (err) => console.error('Collaboration error:', err));

    // Fetch the document state from the server
    await doc.fetch();

    if (!doc.type) {
        // Create a new shared document with initial content
        workbook.getActiveSheet().getCell(0, 0).value("default content");
        await doc.create(workbook.collaboration.toSnapshot(), type.uri, {});

        // Bind the workbook to the shared document for real-time sync
        bind(workbook, doc);
    } else {
        // If shared document already exists, just bind to it
        bind(workbook, doc);
    }
};

Create and update the front-end project configuration: webpack.config.js

const path = require("path");

module.exports = {
  entry: "./public/client.js",
  output: {
    path: path.resolve(__dirname, "public"),
    filename: "client.bundle.js",
  },
  mode: "development",
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: ["style-loader", "css-loader"],
      },
    ],
  },
};

Step 5: Build the Frontend

npm run build

After building, a file named public/client.bundle.js will be created.

Step 6: Deploy the Frontend

Upload the entire public/ folder to any static hosting server (e.g., Nginx, Apache, IIS).


Feature Description

Feature

Description

Real-time Synchronization

Edits on one client appear instantly on all others sharing the same document room.

Document Persistence

Server stores snapshots and operational history using SQLite.

Frontend–Backend Separation

Each part can be deployed and scaled independently.

WebSocket Communication

Lightweight and efficient real-time connection.

Cross-Platform Hosting

Works across any static web host and Node.js environment.

Usage Instructions

Step 1: Start the Backend

cd collaboration-server
npm run start

Expected output: Collaboration server listening on port 8080

Step 2: Host the Frontend

Deploy collaboration-client/public/ to your static server.

Step 3: Test Real-Time Collaboration

  1. Open the frontend page in multiple browsers or devices.

  2. Edit any cell in one instance.

  3. Observe the changes reflected instantly on all connected clients.