Skip to content

Commit 515777b

Browse files
kruscheclaudeFelixTJDietrich
authored
feat(library): add a fully-external build entry and externalize Yjs (#782)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Felix T.J. Dietrich <felix_dietrich@gmx.de>
1 parent d03f562 commit 515777b

13 files changed

Lines changed: 231 additions & 91 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@tumaet/apollon": minor
3+
---
4+
5+
Two packaging improvements for embedding hosts. First, `yjs` and `y-protocols` are now required peer dependencies instead of being bundled, so your app and Apollon share a single Yjs instance — no duplicate payload and no cross-instance document errors. Second, a new `@tumaet/apollon/external` entry exposes the same imperative `ApollonEditor` API as the default entry but leaves **every** dependency external (React, MUI, emotion, xyflow, @dnd-kit, zustand, uuid, @chenglou/pretext, …) — so a bundler host of any framework resolves and de-duplicates each one from its own `node_modules` and gets full supply-chain / SBOM visibility, instead of a copy inlined invisibly into the bundle. The default `@tumaet/apollon` (self-contained) and `@tumaet/apollon/react` entries are unchanged. Action required only if you adopt the new entry or the Yjs peer: install the corresponding peers (most package managers do this automatically).

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,13 @@ This monorepo contains every piece of the Apollon platform:
1515
## Use the library
1616

1717
```sh
18-
npm install @tumaet/apollon
18+
npm install @tumaet/apollon yjs y-protocols
1919
```
2020

21-
See the [library README](./library/README.md) for the API.
21+
`yjs` and `y-protocols` are required peer dependencies — they power Apollon's
22+
document model and undo/redo (and live collaboration when enabled), kept
23+
external so the host owns a single Yjs instance. See the
24+
[library README](./library/README.md) for the API and the other build entries.
2225

2326
## Run the stack locally
2427

docs/library/embedding/angular.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ description: Embed Apollon in an Angular host using the default standalone bundl
77
# Angular
88

99
Use the **standalone subpath** (`@tumaet/apollon`). Angular hosts get the
10-
editor with **zero peer deps** to install — React is bundled inside the
11-
tarball.
10+
editor with React bundled inside the tarball; the only peers to install are
11+
`yjs` and `y-protocols` (`npm install @tumaet/apollon yjs y-protocols`).
1212

1313
```ts
1414
import {

docs/library/embedding/install.md

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,32 @@ description: Install @tumaet/apollon — pick the standalone or /react subpath.
66

77
# Install
88

9+
`yjs` and `y-protocols` are required peer dependencies of **every** build — they
10+
power Apollon's document model and undo/redo (and live collaboration when
11+
enabled), so the editor needs them whether or not you collaborate. Keeping them
12+
external lets a host that already uses Yjs share a single instance instead of a
13+
private, possibly mismatched copy. Most package managers install missing peers
14+
automatically.
15+
916
## Standalone build (any framework)
1017

1118
```sh
12-
npm install @tumaet/apollon
19+
npm install @tumaet/apollon yjs y-protocols
1320
```
1421

1522
```ts
1623
import { ApollonEditor } from "@tumaet/apollon"
1724
import "@tumaet/apollon/style.css"
1825
```
1926

20-
No further installs — React, MUI, emotion, and xyflow are bundled inside the library tarball.
27+
React, MUI, emotion, and xyflow are bundled inside the library tarball; only
28+
`yjs` and `y-protocols` are peers you provide.
2129

2230
## Peer-dependency build (React hosts)
2331

2432
```sh
2533
npm install @tumaet/apollon \
34+
yjs y-protocols \
2635
react react-dom \
2736
@emotion/react @emotion/styled @mui/material @xyflow/react
2837
```
@@ -32,19 +41,47 @@ import { ApollonEditor } from "@tumaet/apollon/react"
3241
import "@tumaet/apollon/style.css"
3342
```
3443

44+
`yjs` and `y-protocols` are required for every build; the React, MUI, emotion,
45+
and xyflow peers below are needed by the `/react` and `/external` builds.
46+
3547
| Peer | Range |
3648
| ----------------- | ---------- |
37-
| `react` | `^18.3.0` |
38-
| `react-dom` | `^18.3.0` |
49+
| `yjs` | `^13.6.0` |
50+
| `y-protocols` | `^1.0.6` |
51+
| `react` | `^19.0.0` |
52+
| `react-dom` | `^19.0.0` |
3953
| `@mui/material` | `^6.4.0` |
40-
| `@emotion/react` | `^11.11.0` |
41-
| `@emotion/styled` | `^11.11.0` |
42-
| `@xyflow/react` | `^12.3.0` |
54+
| `@emotion/react` | `^11.12.0` |
55+
| `@emotion/styled` | `^11.12.0` |
56+
| `@xyflow/react` | `^12.9.0` |
4357

4458
The `/react` subpath keeps your final bundle from shipping a second copy of
4559
React. It is also the entry that exports the `<Apollon>` React component — the
4660
recommended way to embed in React. See [React](/library/embedding/react).
4761

62+
## Fully external build (any bundler host)
63+
64+
```sh
65+
npm install @tumaet/apollon \
66+
yjs y-protocols \
67+
react react-dom \
68+
@emotion/react @emotion/styled @mui/material @xyflow/react
69+
```
70+
71+
```ts
72+
import { ApollonEditor } from "@tumaet/apollon/external"
73+
import "@tumaet/apollon/style.css"
74+
```
75+
76+
Same imperative `ApollonEditor` API as the default entry, but **every**
77+
dependency is external — the React family above _and_ Apollon's own runtime
78+
deps (`@dnd-kit`, `zustand`, `uuid`, `@chenglou/pretext`), which arrive
79+
transitively with the package. Your bundler resolves and de-duplicates each one
80+
against your app's `node_modules`, and your bundle analyzer / SBOM tooling sees
81+
them as real packages instead of code inlined invisibly into one chunk. Use it
82+
from any framework with a bundler, including non-React ones (the editor still
83+
runs on the React you provide internally; your own code never touches it).
84+
4885
## Type definitions
4986

50-
Types ship with the package (`dist/index.d.ts`) and are identical for both subpaths. Requires TypeScript 5.0+ with `moduleResolution: "bundler" | "node16" | "nodenext"`.
87+
Types ship with the package (`dist/index.d.ts`) and are identical for every subpath. Requires TypeScript 5.0+ with `moduleResolution: "bundler" | "node16" | "nodenext"`.

docs/library/embedding/vanilla.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ description: Drop Apollon into a plain HTML page with one script tag.
99
The standalone subpath works as a single ESM module loaded directly from a
1010
CDN. No build step, no bundler.
1111

12+
`yjs` and `y-protocols` are required peers, but on the CDN path esm.sh resolves
13+
and serves them from the import URL automatically — there is nothing extra to
14+
load. (With a bundler you install the peers yourself — see
15+
[Install](/library/embedding/install).)
16+
1217
```html
1318
<link rel="stylesheet" href="https://esm.sh/@tumaet/apollon@4.8.0/style.css" />
1419
<div id="apollon" style="width: 100%; height: 600px"></div>

docs/library/overview.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,15 @@ Apollon ships as an npm library that any framework can embed. The public API is
1414

1515
13 UML and modeling diagram types · SVG/PNG/PDF/JSON export · optional real-time collaboration via Yjs · injectable [canvas overlay controls](/library/api/overlay-controls).
1616

17-
## Two builds, one API
17+
## Three builds, one API
1818

19-
| Subpath | React / MUI / emotion / xyflow | Bundle | When to use |
20-
| ----------------------------- | ------------------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
21-
| `@tumaet/apollon` _(default)_ | bundled | ~2.4 MB | Any framework that doesn't already have React installed — Angular (the primary use case for [Artemis](https://artemis.tum.de/)), Vue, Svelte, vanilla JS. Zero peer deps to install. |
22-
| `@tumaet/apollon/react` | externalized | ~875 KB | React 18.3 hosts that want to share their React instance with the editor and dedupe the bundle. |
19+
| Subpath | Dependencies | Bundle | When to use |
20+
| ----------------------------- | ------------------------ | ------- | -------------------------------------------------------------------------------------------------------------------------------- |
21+
| `@tumaet/apollon` _(default)_ | all bundled (except Yjs) | ~2.4 MB | No bundler — vanilla JS, a `<script>` tag, or a CDN. Self-contained; only `yjs` + `y-protocols` to install. |
22+
| `@tumaet/apollon/react` | React family external | ~875 KB | A React host that shares its own React/MUI and wants the `<Apollon>` component. |
23+
| `@tumaet/apollon/external` | everything external | ~840 KB | A bundler host of any framework — Angular, Vue, Svelte, React — that wants one shared, fully auditable copy of every dependency. |
2324

24-
`peerDependenciesMeta.optional` covers all six peers `npm install @tumaet/apollon` never warns about missing React.
25+
`peerDependenciesMeta.optional` covers the six React-family peers, so `npm install @tumaet/apollon` never warns about missing React. `yjs` and `y-protocols` are required peers of all builds — they power Apollon's document model and undo/redo (and live collaboration when enabled), so the editor needs them either way, and keeping them external lets a host that already uses Yjs own a single instance. Most package managers add them automatically. The `/external` entry additionally externalizes Apollon's own runtime deps (`@dnd-kit`, `zustand`, `uuid`, `@chenglou/pretext`), which install transitively with the package.
2526

2627
## What's next
2728

docs/library/quickstart.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,15 @@ idiomatic version — but the two steps below are all Apollon needs.
1313
## 1. Install
1414

1515
```sh
16-
npm install @tumaet/apollon
16+
npm install @tumaet/apollon yjs y-protocols
1717
```
1818

1919
This is the standalone build: React, MUI, emotion, and xyflow are bundled
20-
inside the tarball, so there are no peer dependencies to install. React hosts
21-
should instead use the `/react` subpath — see [Install](/library/embedding/install).
20+
inside the tarball; `yjs` and `y-protocols` are the only peers you install. They
21+
power Apollon's document model and undo/redo (and live collaboration when
22+
enabled), kept external so a host that already uses Yjs shares one instance.
23+
React hosts should instead use the `/react` subpath — see
24+
[Install](/library/embedding/install).
2225

2326
:::danger The editor MUST have an explicit height
2427
Apollon renders onto a React Flow canvas, which sizes itself to its parent. If

docs/src/pages/index.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ const VANILLA_SNIPPET = `<link
7575
<div id="apollon" style="width: 100%; height: 600px"></div>
7676
7777
<script type="module">
78+
// esm.sh serves Apollon's required yjs/y-protocols peers automatically.
7879
import { ApollonEditor } from "https://esm.sh/@tumaet/apollon@4.8.0"
7980
8081
const saved = localStorage.getItem("diagram")
@@ -111,7 +112,9 @@ function Hero() {
111112
</Link>
112113
</div>
113114
<div className={styles.install}>
114-
<CodeBlock language="bash">npm install @tumaet/apollon</CodeBlock>
115+
<CodeBlock language="bash">
116+
npm install @tumaet/apollon yjs y-protocols
117+
</CodeBlock>
115118
</div>
116119
</div>
117120
</header>
@@ -224,8 +227,9 @@ const WAYS: LinkCard[] = [
224227
body: (
225228
<>
226229
<code>@tumaet/apollon</code> on npm. Framework-agnostic by default;
227-
Angular hosts install <strong>zero peer deps</strong>. A{" "}
228-
<code>/react</code> subpath dedupes React when the host already has it.
230+
Angular hosts install just <code>yjs</code> + <code>y-protocols</code>.
231+
A <code>/react</code> subpath dedupes React when the host already has
232+
it.
229233
</>
230234
),
231235
to: "/library/",

docs/user/overview.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ versioned and reviewed like any other source.
5454
you need UML modeling inside an existing application.
5555

5656
```sh
57-
npm install @tumaet/apollon
57+
npm install @tumaet/apollon yjs y-protocols
5858
```
5959

6060
| You want to... | Use this |

library/README.md

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -29,32 +29,36 @@ Apollon is the modeling editor behind [Artemis](https://artemis.tum.de/), TUM's
2929

3030
## Install
3131

32-
The package ships two builds with the same API. Pick one based on whether your host already uses React:
32+
The package ships three builds with the same imperative API. Pick one based on how your host bundles (or doesn't):
3333

34-
| Import | React / MUI / emotion / xyflow | Size (min / gzip) | Use when |
35-
| ----------------------------- | ------------------------------ | ----------------- | ------------------------------------------------------------------------------------------------------- |
36-
| `@tumaet/apollon` _(default)_ | **bundled** | ~2.4 MB / ~540 KB | Your host is Angular, Vue, Svelte, or vanilla JS. No peer deps to install. |
37-
| `@tumaet/apollon/react` | **peer deps** (shared) | ~875 KB / ~170 KB | Your host is React 18.3 and should share its React and MUI with the editor instead of duplicating them. |
34+
| Import | Dependencies | Size (min / gzip) | Use when |
35+
| ----------------------------- | ---------------------------- | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
36+
| `@tumaet/apollon` _(default)_ | **all bundled** (except Yjs) | ~2.4 MB / ~540 KB | No bundler — vanilla JS, a `<script>` tag, or a CDN. Self-contained; only `yjs` + `y-protocols` to install. |
37+
| `@tumaet/apollon/react` | **React family external** | ~875 KB / ~170 KB | A React host that shares its own React and MUI with the editor. Also ships the `<Apollon>` component, hooks, provider. |
38+
| `@tumaet/apollon/external` | **everything external** | ~840 KB / ~175 KB | A bundler host (Angular, Vue, Svelte, React) that wants every dependency resolved from its own `node_modules` — one shared copy and full SBOM / audit visibility. |
3839

39-
Sizes are the published entry chunks. Gzip is the transfer size. The `/react` number excludes the peers your app already ships.
40+
Sizes are the published entry chunks. Gzip is the transfer size. The `/react` and `/external` numbers exclude the peers your app already ships.
4041

41-
### Standalone build (any framework, no peer deps)
42+
`yjs` and `y-protocols` are required peer dependencies of **all three** builds — they power Apollon's document model and undo/redo (and live collaboration when you enable it), so every editor needs them, collaboration or not. Keeping them external means a host that already uses Yjs (or a second Apollon on the page) shares a single Yjs instance instead of loading a private, possibly mismatched copy. Most package managers install missing peers automatically; the explicit commands below are listed for clarity.
43+
44+
### Standalone build (any framework)
4245

4346
```sh
44-
npm install @tumaet/apollon
47+
npm install @tumaet/apollon yjs y-protocols
4548
```
4649

4750
```ts
4851
import { ApollonEditor } from "@tumaet/apollon"
4952
import "@tumaet/apollon/style.css"
5053
```
5154

52-
React, MUI, emotion, and xyflow are bundled in. Nothing else to install.
55+
React, MUI, emotion, and xyflow are bundled in; only `yjs` and `y-protocols` are peers you provide.
5356

5457
### React build (share your host's React)
5558

5659
```sh
5760
npm install @tumaet/apollon \
61+
yjs y-protocols \
5862
react react-dom \
5963
@emotion/react @emotion/styled @mui/material @xyflow/react
6064
```
@@ -64,18 +68,36 @@ import { Apollon } from "@tumaet/apollon/react"
6468
import "@tumaet/apollon/style.css"
6569
```
6670

67-
| Peer | Range | | Peer | Range |
68-
| --------------- | --------- | --- | ----------------- | ---------- |
69-
| `react` | `^18.3.0` | | `@mui/material` | `^6.4.0` |
70-
| `react-dom` | `^18.3.0` | | `@emotion/react` | `^11.11.0` |
71-
| `@xyflow/react` | `^12.3.0` | | `@emotion/styled` | `^11.11.0` |
71+
`yjs` and `y-protocols` are required for all builds; the React, MUI, emotion, and xyflow peers below are specific to the `/react` and `/external` builds.
7272

73-
## Which build do I use?
73+
| Peer | Range | | Peer | Range |
74+
| ------------- | --------- | --- | ----------------- | ---------- |
75+
| `yjs` | `^13.6.0` | | `@mui/material` | `^6.4.0` |
76+
| `y-protocols` | `^1.0.6` | | `@emotion/react` | `^11.12.0` |
77+
| `react` | `^19.0.0` | | `@emotion/styled` | `^11.12.0` |
78+
| `react-dom` | `^19.0.0` | | `@xyflow/react` | `^12.9.0` |
79+
80+
### Fully external build (any bundler host)
81+
82+
```sh
83+
npm install @tumaet/apollon \
84+
yjs y-protocols \
85+
react react-dom \
86+
@emotion/react @emotion/styled @mui/material @xyflow/react
87+
```
88+
89+
```ts
90+
import { ApollonEditor } from "@tumaet/apollon/external"
91+
import "@tumaet/apollon/style.css"
92+
```
93+
94+
Same imperative `ApollonEditor` API as the default entry, but **every** dependency is left external — the React family above _and_ Apollon's own runtime deps (`@dnd-kit`, `zustand`, `uuid`, `@chenglou/pretext`), which arrive transitively when you install the package. Your bundler then resolves and de-duplicates each one against your app's `node_modules`, and your bundle analyzer / SBOM tooling sees them as the real packages they are instead of code inlined invisibly into one chunk. Use this from any framework with a bundler — even a non-React one (the editor still runs on the React you provide internally; your own code never touches it).
7495

75-
It comes down to whether your host already runs React:
96+
## Which build do I use?
7697

77-
- **Not a React app?** Use the default `@tumaet/apollon`. It bundles its own React, so there is nothing extra to install or configure.
78-
- **A React app?** Use `@tumaet/apollon/react` and install the peers above. The default build bundles its own React, so in a React app you would load two copies. That causes "Invalid hook call" errors and a larger bundle. The `/react` subpath leaves React, MUI, emotion, and xyflow external so the editor shares the copies your app already has. It is also the only entry that exports the `<Apollon>` component, hooks, and provider.
98+
- **No bundler** (vanilla JS, `<script>`, CDN)? Use the default `@tumaet/apollon`. It inlines its own React, so the only peers to install are `yjs` and `y-protocols`.
99+
- **A React app?** Use `@tumaet/apollon/react` and install the peers above. The default build bundles its own React, so in a React app you would load two copies — that causes "Invalid hook call" errors and a larger bundle. The `/react` subpath leaves React, MUI, emotion, and xyflow external so the editor shares the copies your app already has. It is also the only entry that exports the `<Apollon>` component, hooks, and provider.
100+
- **A bundler host that wants one shared, fully auditable copy of every dependency?** Use `@tumaet/apollon/external` and install the peers above. Works from any framework.
79101

80102
> **⚠️ Give the container an explicit, non-zero height** (`600px`, `80vh`, or a sized flex/grid child), whichever build you use. The canvas sizes itself to its parent, so with no resolvable height it collapses to zero pixels and renders blank. This is the most common embedding mistake. See [Troubleshooting](https://ls1intum.github.io/Apollon/library/troubleshooting).
81103
@@ -178,6 +200,8 @@ export class DiagramEditorComponent {
178200

179201
### Vanilla JS / CDN
180202

203+
`yjs` and `y-protocols` are required peers, but on the CDN path esm.sh resolves and serves them from the import URL automatically — there is nothing extra to load. (With a bundler you install the peers yourself.)
204+
181205
```html
182206
<link rel="stylesheet" href="https://esm.sh/@tumaet/apollon@4.8.0/style.css" />
183207
<div id="apollon" style="width: 100%; height: 600px"></div>

0 commit comments

Comments
 (0)