Перейти к содержимому

SvelteKit

Это содержимое пока не доступно на вашем языке.

XenolithGraph ships a Svelte adapter (@xenolithengine/graph-svelte) and a framework-agnostic Web Component (@xenolithengine/graph-wc). Both run only in the browser, so SvelteKit needs to be told to skip them on the server.

Install

Terminal window
pnpm add @xenolithengine/graph-editor @xenolithengine/graph-svelte pixi.js
# or, for the framework-agnostic web-component path:
pnpm add @xenolithengine/graph-editor @xenolithengine/graph-wc pixi.js

pixi.js is a peer dependency.

src/routes/editor/+page.svelte
<script lang="ts">
import { browser } from '$app/environment'
import { onMount } from 'svelte'
let Editor: any = null
onMount(async () => {
if (browser) Editor = (await import('$lib/Editor.svelte')).default
})
</script>
{#if Editor}
<svelte:component this={Editor} />
{:else}
<div style="height:100vh;background:#121212;"></div>
{/if}
src/lib/Editor.svelte
<script lang="ts">
import { xenolith, createXenolithStores } from '@xenolithengine/graph-svelte'
import { myGraph } from '$lib/data'
const stores = createXenolithStores()
function onReady(e: CustomEvent<XenolithEditor>) {
stores.editor.set(e.detail)
// imperative setup: register schemas, fitView, …
}
</script>
<div
use:xenolith={{ graph: myGraph, fitOnLoad: true, minimap: true }}
on:ready={onReady}
on:node-click={(e) => console.log('clicked', e.detail.nodeId)}
style="height:100vh"
></div>

The Svelte adapter is an action (use:xenolith={props}) rather than a component. Pass the graph + options as props; the action dispatches ready (detail: the XenolithEditor) once mounted, then re-dispatches every editor event off the host element as a kebab-named CustomEvent (node-click, edge-connected, selection-changed, …) with typed payloads. Wire reactive stores (nodes, selection, undoRedo, the controlled nodesState() triple, …) from on:ready — see the Svelte guide.

Pattern 2 — Web Component (framework-neutral)

src/routes/editor/+page.svelte
<script lang="ts">
import { browser } from '$app/environment'
import { onMount } from 'svelte'
import { myGraph } from '$lib/data'
let el: HTMLElement
onMount(async () => {
if (!browser) return
const { register } = await import('@xenolithengine/graph-wc')
register() // defines <xenolith-graph>
// The WC takes `graph` via the JS property — set it after the element is in the DOM and the
// editor mounts itself + loads it. `ready` fires once with the editor; no polling needed.
el.addEventListener('ready', (e) => {
const editor = (e as CustomEvent).detail
// imperative setup: register schemas, custom plugins
})
;(el as any).graph = myGraph
;(el as any).setAttribute('fit-on-load', '')
})
</script>
<xenolith-graph bind:this={el} class="xeno" minimap style="display:block;height:100vh"></xenolith-graph>

Disable SSR for editor routes

If a route ONLY renders the editor:

src/routes/editor/+page.ts
export const ssr = false

Use this when the route’s only purpose is the editor — keep SSR enabled for content-heavy routes.

Why no SSR mode

The renderer needs WebGL + a real <canvas>. There’s no static-HTML output mode. If you need a server-rendered preview of a graph (a thumbnail in a list, an OG card), call editor.exportImage() on the client and upload the PNG.

Vite config — dedupe PIXI

If you import PIXI from multiple places, keep a single physical copy:

vite.config.ts
export default defineConfig({
resolve: { dedupe: ['pixi.js'] },
optimizeDeps: { include: ['pixi.js'] },
})

PIXI’s extension registry throws “Extension type X already has a handler” if you load it twice — same trap we hit in our own monorepo.