observablehq / plot

A concise API for exploratory data visualization implementing a layered grammar of graphics
https://observablehq.com/plot/
ISC License
4.27k stars 174 forks source link

Server-side rendering in Svelte #1550

Closed beingflo closed 1 year ago

beingflo commented 1 year ago

Using plot in Svelte is very easy with the integration described here. However this approach does not seem to support SSR out of the box. I've seen the examples in the docs, but they are about React and Vue, both virtual DOM frameworks. I'm wondering if some brief documentation can be added to lay out how one would go about server-side rendering in Svelte, SolidJS or other compiler assisted frameworks. Thanks a lot for the good work!

mbostock commented 1 year ago

I’m not enough of an expert with Svelte to know whether there’s a way to write a JavaScript component that generates DOM server-side with Svelte. If someone can point me to some examples, I’d be happy to investigate, but a preliminary read of Svelte’s documentation doesn’t suggest how this might be possible.

beingflo commented 1 year ago

Thanks for the quick reply! I should have mentioned that I'm trying to get it working in SvelteKit. From some experimentation and asking on the SvelteKit discord I think it should be possible:

<script lang="ts">
    import * as Plot from '@observablehq/plot';

    const plot = `<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"> <circle cx="50" cy="50" r="50" /> </svg>`;
</script>

{@html plot}

This will prerender the svg, I can see it in the server response. Now, the only obstacle I suppose is the absence of document.

If I try this

<script lang="ts">
    import * as Plot from '@observablehq/plot';

    const plot = Plot.lineY([
        { x: 1, y: 1 },
        { x: 2, y: 2 },
    ]).plot();
</script>

{@html plot}

I get this error: Cannot read properties of undefined (reading 'documentElement')

karimfromjordan commented 1 year ago

I’m not enough of an expert with Svelte to know whether there’s a way to write a JavaScript component that generates DOM server-side with Svelte. If someone can point me to some examples, I’d be happy to investigate, but a preliminary read of Svelte’s documentation doesn’t suggest how this might be possible.

I think what you are referring to might be this: https://svelte.dev/docs#template-syntax-svelte-element

mbostock commented 1 year ago

Thanks for the guidance. I think {@html …} is what we’ll want here. We just need to pass Plot a DOM implementation that we can serialize to a string. JSDOM would work, but we can also adapt the tiny implementation I’ve written here:

https://github.com/observablehq/plot/blob/0a38eb8ca7b1a5e91f42d842bb030f45f294de66/docs/components/PlotRender.js#L4-L111

beingflo commented 1 year ago

Ok this seems to get rid of the error and I can see that the result of plot is an object which contains all the relevant bits. To adapt the toHyperScript from the vue example I used this library, let me know if this makes any sense, I'm just throwing mud at the wall at this point. This seems to give me a valid svg element, but I still don't manage to add it to the page. {@html } doesn't seem to do anything. Any clue how to proceed?