CSP data:-Fonts + Doku: Excalidraw als sechstes Standard-Plugin #143

Merged
fable-5 merged 2 commits from excalidraw-demo-docs into main 2026-07-19 22:41:27 +02:00
10 changed files with 57 additions and 19 deletions

View File

@ -29,7 +29,10 @@ export function buildPluginFrameCsp(assetBase: string): string {
`script-src ${assetBase}`, `script-src ${assetBase}`,
`style-src ${assetBase} 'unsafe-inline'`, `style-src ${assetBase} 'unsafe-inline'`,
`img-src ${assetBase} data: blob:`, `img-src ${assetBase} data: blob:`,
`font-src ${assetBase}`, // `data:` so a saved sketch SVG with embedded (subsetted) fonts — the
// Excalidraw plugin stores those — renders its handwriting look in the
// snapshot view too. data: fonts make no network request.
`font-src ${assetBase} data:`,
// A plugin may talk to its OWN version-pinned assets (bundled apps like // A plugin may talk to its OWN version-pinned assets (bundled apps like
// drawio lazy-load stencils/resources via XHR) — and to nothing else: // drawio lazy-load stencils/resources via XHR) — and to nothing else:
// no api, no external hosts. The zero-external-network guarantee holds. // no api, no external hosts. The zero-external-network guarantee holds.

View File

@ -28,7 +28,11 @@ server {
# from this origin only (the GDPR "zero external requests" posture). # from this origin only (the GDPR "zero external requests" posture).
# `style-src 'unsafe-inline'` covers the app's inline style attributes # `style-src 'unsafe-inline'` covers the app's inline style attributes
# (CSS custom properties, layout); scripts are all external files. # (CSS custom properties, layout); scripts are all external files.
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; font-src 'self'; img-src 'self' data: blob:; connect-src 'self'; worker-src 'self'; manifest-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'" always; # font-src includes `data:` for the subsetted fonts Excalidraw embeds
# into saved sketch SVGs (inlined by the plugin fallback renderer on
# public pages). data: fonts trigger no network request, so the
# zero-third-party-request guarantee (security.md) is unaffected.
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; font-src 'self' data:; img-src 'self' data: blob:; connect-src 'self'; worker-src 'self'; manifest-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'" always;
add_header X-Content-Type-Options "nosniff" always; add_header X-Content-Type-Options "nosniff" always;
try_files $uri /index.html; try_files $uri /index.html;
} }

View File

@ -128,6 +128,12 @@ person looking at it could.
build time into `vendor/`, gitignored) and runs fullscreen in the build time into `vendor/`, gitignored) and runs fullscreen in the
sandbox; blocks store `{ xml, svg }`, render mode and exports use the sandbox; blocks store `{ xml, svg }`, render mode and exports use the
SVG snapshot. SVG snapshot.
- `excalidraw` (`block`): hand-drawn sketches — proves the npm-library
flavor of the bundled-app path: the Excalidraw React editor is bundled
straight into `plugin.js` (esbuild) with its font/locale assets shipped
alongside and loaded via `EXCALIDRAW_ASSET_PATH`; blocks store
`{ scene, svg }`, render mode and exports use the SVG snapshot (with
subsetted fonts embedded as `data:` URIs).
These live in `packages/plugins/` in the monorepo, are built by CI, and These live in `packages/plugins/` in the monorepo, are built by CI, and
double as the plugin-SDK integration tests. double as the plugin-SDK integration tests.

View File

@ -76,9 +76,13 @@ auszuführen.
Ein Plugin darf eine ganze Unter-Anwendung als Assets mitbringen und in Ein Plugin darf eine ganze Unter-Anwendung als Assets mitbringen und in
einem Kind-iframe seines eigenen Asset-Pfads ausführen — so bettet das einem Kind-iframe seines eigenen Asset-Pfads ausführen — so bettet das
`drawio`-Plugin den echten draw.io-Editor ein. Kombiniere das mit `drawio`-Plugin den echten draw.io-Editor ein. Das `excalidraw`-Plugin
`host.ui.enterFullscreen()` für Editoren, die den ganzen Bildschirm zeigt die andere Spielart derselben Idee: eine npm-React-Bibliothek,
brauchen. Größen-Limits: 64 MiB ZIP, 256 MiB entpackt. per esbuild direkt in die `plugin.js` gebündelt und im Frame selbst im
Vollbild gemountet, mit ihren Laufzeit-Assets (Fonts, Sprachen) im ZIP.
Kombiniere das mit `host.ui.enterFullscreen()` für Editoren, die den
ganzen Bildschirm brauchen. Größen-Limits: 64 MiB ZIP, 256 MiB
entpackt.
### Entwickeln und ausliefern ### Entwickeln und ausliefern

View File

@ -97,20 +97,22 @@ zeigen den Fallback-Text des Plugins, wenn es fehlt.
Mitgelieferte Referenz-Plugins: `toc` (Inhaltsverzeichnis), Mitgelieferte Referenz-Plugins: `toc` (Inhaltsverzeichnis),
`page-index` (label-gefilterte Seitenliste), `mermaid` `page-index` (label-gefilterte Seitenliste), `mermaid`
(Diagramm-Blöcke), `drawio` (vollwertiges draw.io-Bearbeiten), (Diagramm-Blöcke), `drawio` (vollwertiges draw.io-Bearbeiten),
`section-styles-basic` (farbige Hinweiskästen). `excalidraw` (handgezeichnete Skizzen), `section-styles-basic`
(farbige Hinweiskästen).
**Woher kommen die ZIPs der Referenz-Plugins?** Sie liegen den **Woher kommen die ZIPs der Referenz-Plugins?** Sie liegen den
Server-Images nicht bei — sie werden aus dem Repository gebaut (Node 22 Server-Images nicht bei — sie werden aus dem Repository gebaut (Node 22
und pnpm, einmalig `pnpm install` im Repo-Wurzelverzeichnis): und pnpm, einmalig `pnpm install` im Repo-Wurzelverzeichnis):
```sh ```sh
cd packages/plugins/<name> # toc | page-index | mermaid | drawio | section-styles-basic cd packages/plugins/<name> # toc | page-index | mermaid | drawio | excalidraw | section-styles-basic
pnpm build # → dist/<id>-<version>.zip — diese Datei hochladen pnpm build # → dist/<id>-<version>.zip — diese Datei hochladen
``` ```
Der `drawio`-Build lädt beim ersten Lauf sein gepinntes Editor-Bundle Der `drawio`-Build lädt beim ersten Lauf sein gepinntes Editor-Bundle
von GitHub und packt ein ~27-MiB-ZIP (innerhalb des 64-MiB-Limits für von GitHub und packt ein ~27-MiB-ZIP (innerhalb des 64-MiB-Limits für
Plugin-Uploads); die anderen vier bauen offline in Sekunden. Plugin-Uploads); `excalidraw` bündelt seinen Editor aus npm in ein
~16-MiB-ZIP; die übrigen vier bauen offline in Sekunden.
**Typischer Ablauf:** ZIP hochladen, die abgeschottete Vorschau prüfen, **Typischer Ablauf:** ZIP hochladen, die abgeschottete Vorschau prüfen,
den Instanz-Modus auf `optional` stellen und das Plugin dann je Teich den Instanz-Modus auf `optional` stellen und das Plugin dann je Teich

View File

@ -38,7 +38,7 @@ anderen Seiten noch an deinem Konto etwas ändern.
## Ein Blick voraus ## Ein Blick voraus
Dorfteich bringt fünf Standard-Plugins mit — von der Diagramm-Zeichnung Dorfteich bringt sechs Standard-Plugins mit — von der Diagramm-Zeichnung
bis zum automatischen Inhaltsverzeichnis. Die stellen wir im nächsten bis zum automatischen Inhaltsverzeichnis. Die stellen wir im nächsten
Kapitel einzeln vor, und du siehst sie dort auch in Nadias Teich im Kapitel einzeln vor, und du siehst sie dort auch in Nadias Teich im
Einsatz. Einsatz.

View File

@ -1,9 +1,9 @@
# Die Standard-Bausteine im Schaufenster # Die Standard-Bausteine im Schaufenster
Dorfteich bringt fünf Plugins mit. Dieses Kapitel ist ein Dorfteich bringt sechs Plugins mit. Dieses Kapitel ist ein
Schaufensterbummel: je ein Blick, wofür jeder Baustein gut ist — ohne Schaufensterbummel: je ein Blick, wofür jeder Baustein gut ist — ohne
Bedienungsanleitung. (Die beiden Diagramm-Bausteine haben eigene kleine Bedienungsanleitung. (Die Diagramm- und Zeichen-Bausteine haben eigene
Welten; hier geht es nur darum, dass du weißt, was es gibt.) kleine Welten; hier geht es nur darum, dass du weißt, was es gibt.)
## Mermaid-Diagramm — Diagramme aus Text ## Mermaid-Diagramm — Diagramme aus Text
@ -33,6 +33,19 @@ skizziert.
![Nadias Routen-Skizze aus dem draw.io-Baustein](img/19-drawio-gravel.png) ![Nadias Routen-Skizze aus dem draw.io-Baustein](img/19-drawio-gravel.png)
## Excalidraw — Skizzen wie von Hand
Der dritte Zeichen-Baustein, und der lockerste: **Excalidraw** öffnet
sich ebenfalls im Vollbild, zeichnet aber im Handschrift-Look — Kästen
wirken hingeworfen, Beschriftungen wie mit dem Stift geschrieben.
Perfekt für schnelle Ideen, Lagepläne und alles, was bewusst nach
Entwurf aussehen soll statt nach fertigem Diagramm.
Nadia hat damit auf ihrer Seite
[Konzerte & Live](https://dorfteich.online/public/nadia-morgenstern/konzerte-live)
den Bühnenplan fürs nächste Open-Air gekritzelt — samt Merker, wo der
beste Platz ist.
## Inhaltsverzeichnis — lange Seiten gliedern ## Inhaltsverzeichnis — lange Seiten gliedern
Ein **Seiten-Werkzeug**: Es sitzt hinter dem Werkzeug-Symbol in der Ein **Seiten-Werkzeug**: Es sitzt hinter dem Werkzeug-Symbol in der

View File

@ -70,7 +70,10 @@ without ever executing plugin code.
A plugin may ship an entire sub-application as assets and run it in a A plugin may ship an entire sub-application as assets and run it in a
child iframe of its own asset path — that is how the `drawio` plugin child iframe of its own asset path — that is how the `drawio` plugin
embeds the real draw.io editor. Combine with embeds the real draw.io editor. The `excalidraw` plugin shows the other
flavor of the same idea: an npm React library bundled directly into
`plugin.js` (esbuild) and mounted fullscreen in the frame itself, with
its runtime assets (fonts, locales) shipped in the ZIP. Combine with
`host.ui.enterFullscreen()` for editors that need the whole screen. `host.ui.enterFullscreen()` for editors that need the whole screen.
Size limits: 64 MiB ZIP, 256 MiB unpacked. Size limits: 64 MiB ZIP, 256 MiB unpacked.

View File

@ -88,20 +88,22 @@ fallback text when it is missing.
Shipped reference plugins: `toc` (table of contents), `page-index` Shipped reference plugins: `toc` (table of contents), `page-index`
(label-filtered page list), `mermaid` (diagram blocks), `drawio` (label-filtered page list), `mermaid` (diagram blocks), `drawio`
(full draw.io editing), `section-styles-basic` (colored callouts). (full draw.io editing), `excalidraw` (hand-drawn sketches),
`section-styles-basic` (colored callouts).
**Getting the reference plugin ZIPs.** They are not bundled with the **Getting the reference plugin ZIPs.** They are not bundled with the
server images — build them from the repository (Node 22 + pnpm, one-time server images — build them from the repository (Node 22 + pnpm, one-time
`pnpm install` at the repo root): `pnpm install` at the repo root):
```sh ```sh
cd packages/plugins/<name> # toc | page-index | mermaid | drawio | section-styles-basic cd packages/plugins/<name> # toc | page-index | mermaid | drawio | excalidraw | section-styles-basic
pnpm build # → dist/<id>-<version>.zip — upload that file pnpm build # → dist/<id>-<version>.zip — upload that file
``` ```
The `drawio` build downloads its pinned editor bundle from GitHub on the The `drawio` build downloads its pinned editor bundle from GitHub on the
first run and packs a ~27 MiB ZIP (within the 64 MiB plugin upload first run and packs a ~27 MiB ZIP (within the 64 MiB plugin upload
limit); the other four build offline in seconds. limit); `excalidraw` bundles its editor from npm into a ~16 MiB ZIP; the
remaining four build offline in seconds.
**Typical rollout:** upload the ZIP, check the sandboxed preview, switch **Typical rollout:** upload the ZIP, check the sandboxed preview, switch
the instance mode to `optional`, then enable the plugin per pond (pond the instance mode to `optional`, then enable the plugin per pond (pond

View File

@ -5,9 +5,10 @@
* page lists their licenses. Adding a font is a change here + an image rebuild * page lists their licenses. Adding a font is a change here + an image rebuild
* there is no runtime font management (deliberately small surface). * there is no runtime font management (deliberately small surface).
* *
* Fonts are served only from the instance itself (`font-src 'self'`); a * Fonts are served only from the instance itself (`font-src 'self' data:`
* visitor's browser makes zero third-party requests (the GDPR guarantee, * the `data:` part covers fonts embedded inline in saved plugin SVGs, e.g.
* security.md). * Excalidraw sketches); a visitor's browser makes zero third-party requests
* (the GDPR guarantee, security.md).
*/ */
export type FontCategory = 'sans-serif' | 'serif' | 'monospace'; export type FontCategory = 'sans-serif' | 'serif' | 'monospace';
export type FontLicense = 'OFL-1.1' | 'Apache-2.0'; export type FontLicense = 'OFL-1.1' | 'Apache-2.0';