[]
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).
Complete the Real-Time Collaborative Workbook
Foundational knowledge of Database Adapter
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.).
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.jsonmkdir collaboration-server && cd collaboration-server
npm init -y{
"name": "collaboration-server",
"version": "1.0.0",
"type": "module",
"scripts": {
"start": "node ./server.js"
},
"dependencies": {}
}npm install @mescius/js-collaboration @mescius/js-collaboration-ot
npm install @mescius/spread-sheets-collaboration
npm install sqlite3 @mescius/js-collaboration-ot-sqliteimport 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}`);
});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
mkdir collaboration-client && cd collaboration-client
npm init -y{
"name": "collaboration-client",
"version": "1.0.0",
"scripts": {
"build": "webpack"
},
"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-loaderpublic Folder and FilesCreate 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"],
},
],
},
};npm run buildAfter building, a file named public/client.bundle.js will be created.
Upload the entire public/ folder to any static hosting server (e.g., Nginx, Apache, IIS).
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. |
cd collaboration-server
npm run startExpected output: Collaboration server listening on port 8080
Deploy collaboration-client/public/ to your static server.
Open the frontend page in multiple browsers or devices.
Edit any cell in one instance.
Observe the changes reflected instantly on all connected clients.