No description
Find a file
2026-04-03 01:55:49 +02:00
.gitignore first commit 2026-04-02 23:51:20 +02:00
compose.yaml move yml to yaml 2026-04-02 23:53:49 +02:00
Dockerfile first commit 2026-04-02 23:51:20 +02:00
package-lock.json first commit 2026-04-02 23:51:20 +02:00
package.json first commit 2026-04-02 23:51:20 +02:00
README.md first commit 2026-04-02 23:51:20 +02:00
server.js setze toolbar von vertikal zu horizontal 2026-04-03 01:55:49 +02:00

README: Markmap-API mit Docker Compose testen

Diese Anleitung beschreibt ein minimales Setup für einen Docker-Compose-Dienst, der Markdown per HTTP annimmt und als Markmap-HTML rendert. markmap-lib ist das offizielle Paket zur Transformation von Markdown in die Datenstruktur für Markmap.[1][2][3]

Voraussetzungen

  • Docker Engine und Docker Compose Plugin sind installiert.[4][5][6]
  • Ein freier TCP-Port, im Beispiel 3000.[7][4]
  • Eine funktionierende server.js, Dockerfile und docker-compose.yml im selben Projektordner.[6]

Projektstruktur

markmap-api/
├── docker-compose.yml
├── Dockerfile
├── package.json
└── server.js

Dieses Layout entspricht dem üblichen Aufbau einer kleinen Node/Express-App mit Docker Compose.[4][6]

package.json automatisch erzeugen

Die package.json kann automatisch mit npm init -y erzeugt werden; npm erstellt dabei eine Standarddatei im aktuellen Verzeichnis.[8][9][10]

mkdir -p markmap-api
cd markmap-api
npm init -y
npm install express markmap-lib

Nach der Installation trägt npm die Abhängigkeiten automatisch in package.json ein.[11][8]

Beispiel-Dateien

package.json

{
  "name": "markmap-api",
  "version": "1.0.0",
  "private": true,
  "type": "commonjs",
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "express": "^4.21.2",
    "markmap-lib": "^0.18.12"
  }
}

Dockerfile

FROM node:22-alpine

WORKDIR /app

COPY package.json ./
RUN npm install --omit=dev

COPY server.js ./

EXPOSE 3000

CMD ["npm", "start"]

Dieses Container-Muster ist ein übliches Setup für kleine Node-Services in Docker.[5][7][4]

docker-compose.yml

services:
  markmap-api:
    build: .
    container_name: markmap-api
    restart: unless-stopped
    ports:
      - "3000:3000"
    environment:
      PORT: 3000

Docker Compose veröffentlicht damit den Container-Port 3000 auf dem Host-Port 3000.[6][7][4]

server.js

const express = require('express');
const { Transformer } = require('markmap-lib');

const app = express();
const port = process.env.PORT || 3000;

app.use(express.json({ limit: '1mb' }));

app.get('/health', (req, res) => {
  res.json({ ok: true });
});

app.post('/api/markmap', (req, res) => {
  const markdown = req.body?.markdown;

  if (!markdown || typeof markdown !== 'string') {
    return res.status(400).json({ error: 'markdown fehlt oder ist ungültig' });
  }

  try {
    const transformer = new Transformer();
    const { root, features } = transformer.transform(markdown);
    const assets = transformer.getUsedAssets(features);

    const css = (assets.styles || [])
      .map((href) => `<link rel="stylesheet" href="${href}">`)
      .join('\n');

    const js = (assets.scripts || [])
      .map((src) => `<script src="${src}"></script>`)
      .join('\n');

    const html = `<!doctype html>
<html lang="de">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <title>markmap</title>
  <style>
    html, body { margin: 0; height: 100%; background: #fff; }
    #mindmap { width: 100vw; height: 100vh; }
  </style>
  ${css}
</head>
<body>
  <svg id="mindmap"></svg>
  <script>
    window.__MARKMAP_DATA__ = ${JSON.stringify(root)};
  </script>
  <script src="https://cdn.jsdelivr.net/npm/d3@7"></script>
  <script src="https://cdn.jsdelivr.net/npm/markmap-view"></script>
  ${js}
  <script>
    const { Markmap } = window.markmap;
    Markmap.create('#mindmap', null, window.__MARKMAP_DATA__);
  </script>
</body>
</html>`;

    res.setHeader('Content-Type', 'text/html; charset=utf-8');
    res.send(html);
  } catch (err) {
    res.status(500).json({ error: 'Rendering fehlgeschlagen', details: err.message });
  }
});

app.listen(port, '0.0.0.0', () => {
  console.log(`markmap-api läuft auf Port ${port}`);
});

markmap-lib stellt die Transformation und die benötigten Assets für die aktiv genutzten Features bereit.[2][3][1]

Häufiger Syntaxfehler

Wenn in server.js eine Zeile wie console.log(\...`)steht, wurde meist ein Backtick falsch escaped. Template Literals müssen mit echten Backticks geschrieben werden, also z.B.console.log(markmap-api läuft auf Port ${port});`.[12][13]

Container starten

docker compose up --build -d

Mit --build wird das Image neu gebaut, was sinnvoll ist, wenn server.js oder package.json geändert wurden.[5][4][6]

Logs prüfen

docker compose logs -f

Wenn alles korrekt ist, sollte der Dienst nach dem Start auf Port 3000 lauschen.[4][6]

Healthcheck testen

curl http://localhost:3000/health

Erwartete Antwort:

{"ok":true}

API testen

Der Endpoint /api/markmap erwartet JSON mit einem Feld markdown.[1][2]

curl -X POST http://localhost:3000/api/markmap \
  -H 'Content-Type: application/json' \
  -d '{"markdown":"# Projekt\n## Idee A\n## Idee B"}' \
  -o test.html

Die Datei test.html enthält eine renderbare HTML-Seite mit der Markmap und kann im Browser geöffnet werden.[14][1]

Test im Browser

Alternativ kann der Request auch direkt aus einem Tool oder Skript erfolgen; die Antwort ist HTML und nicht JSON.[2][1]

Beispiel mit curl und Header-Anzeige:

curl -i -X POST http://localhost:3000/api/markmap \
  -H 'Content-Type: application/json' \
  -d '{"markdown":"# Demo\n## Alpha\n## Beta"}' | head

Die Response sollte Content-Type: text/html; charset=utf-8 enthalten.[1]

Mit iOS Kurzbefehlen testen

Die Kurzbefehle-App auf iPhone und iPad kann HTTP-Requests an Web-APIs senden, darunter auch POST mit JSON-Body.[15][16]

Empfohlener Shortcut-Ablauf:

  1. Markdown aus Zwischenablage oder Share Sheet holen.[15]
  2. Aktion „Inhalt von URL abrufen“ mit POST auf https://dein-server/api/markmap konfigurieren.[16][15]
  3. Als Body JSON senden, z.B. { "markdown": "<dein Text>" }.[15]
  4. Die HTML-Antwort in Safari oder Quick Look öffnen.[15]

Fehlerbehebung

  • SyntaxError: Invalid or unexpected token: meist falsch kopierte Backticks, typografische Anführungszeichen oder beschädigte Zeichen in server.js.[13][17][18]
  • Container startet neu: docker compose logs -f prüfen und Syntax in server.js gegenchecken.[6][4]
  • Leere Seite im Browser: prüfen, ob CDN-Zugriff auf d3 und markmap-view funktioniert und ob das HTML vollständig ausgeliefert wird.[19][14]
  • Port schon belegt: Host-Port in docker-compose.yml ändern, z.B. 3001:3000.[7][4]

Nächste sinnvolle Schritte

  • Reverse Proxy mit HTTPS davor setzen, z.B. Nginx oder Traefik.[7][4]
  • Optional Basic Auth aktivieren, wenn der Endpoint öffentlich erreichbar ist.[4]
  • Statt HTML eine URL oder gespeicherte SVG/HTML-Datei zurückgeben, wenn der iOS-Workflow sauberer werden soll.[1][15]

Quellen [1] markmap-lib https://markmap.js.org/docs/packages--markmap-lib [2] markmap-lib https://markmap.js.org/api/modules/markmap-lib.html [3] markmap-lib - NPM https://www.npmjs.com/package/markmap-lib [4] An enterprise-style Node.js REST API setup with Docker ... https://codewithhugo.com/node-postgres-express-docker-compose/ [5] Using Docker Compose for NodeJS Development https://www.cloudbees.com/blog/using-docker-compose-for-nodejs-development [6] GitHub - nickjj/docker-node-example: An example Node / Express app that's using Docker and Docker Compose. https://github.com/nickjj/docker-node-example [7] Docker Compose: Node.js Express and MongoDB example https://www.bezkoder.com/docker-compose-nodejs-mongodb/ [8] Creating a package.json file - npm Docs https://docs.npmjs.com/creating-a-package-json-file/ [9] Using npm init with -y flag explained - sebhastian https://sebhastian.com/npm-init-y/ [10] Creating a package.json file https://runebook.dev/en/docs/npm/creating-a-package-json-file [11] So verwenden Sie Node.js-Module mit npm und package.json https://www.digitalocean.com/community/tutorials/how-to-use-node-js-modules-with-npm-and-package-json-de [12] Template-Literale (Template-Zeichenketten) - JavaScript | MDN https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Template_literals [13] SyntaxError: Unerwartetes Token - JavaScript - MDN Web Docs https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Errors/Unexpected_token [14] Try markmap https://markmap.js.org/repl [15] Request your first API in Shortcuts on iPhone or iPad https://support.apple.com/en-il/guide/shortcuts/apd58d46713f/ios [16] Request your first API in Shortcuts on iPhone or iPad https://support.apple.com/en-ae/guide/shortcuts/apd58d46713f/ios [17] SyntaxError: Unexpected token - JavaScript - MDN Web Docs https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Unexpected_token [18] console.log error showing Uncaught SyntaxError - Stack Overflow https://stackoverflow.com/questions/44661360/console-log-error-showing-uncaught-syntaxerror-invalid-or-unexpected-token [19] markmap https://markmap.js.org/api/