Skip to main content

Run Cystoscape.js with Node.js

Table of Contents

Why? If you need to generate an image on the server side.

At first, I thought it was impossible. There is cytosnap that uses Puppeteer (headless browser). Then, for fun, I rewrote it with Tauri.

But later, I though, what if it would be possible to run it with Node.js. And, indeed, it’s possible.

Solution #

Add polyfils for the browser (it also includes canvas):

class XMLSerializer {
  serializeToString(node) {
    return serialize(node);
global.XMLSerializer = XMLSerializer;

const dom = new JSDOM(`<!DOCTYPE html><div id="cy"></div>`);
global.window = dom.window;
global.document = dom.window.document;

Explicitly set bounding box

source.layout.boundingBox = {
  x1: 0,
  y1: 0,
  x2: source.width,
  y2: source.height,

Generate a graph the same way you would in the browser:

const container = dom.window.document.querySelector("#cy");
const cy = cytoscape({ container, ...defaults, ...source });

For now I was able to render it only as SVG:

await loadExtension("svg");
res = cy.svg({
  bg: source.background,
  full: true,

In order to not polute global scope with polyfills we can run this script as sub-process:

const executablePath = `bin/cyto-nodejs.js`;
const bin = spawn(executablePath, args, {
  windowsHide: true,

That’s it.

Source code #

Source code is here:

Read more: Tauri instead of Puppeteer or Playwright?, Server-side UI Components