Skip to content

Commit cc5a23f

Browse files
committed
Prerender chart API endpoints for Cloudflare compatibility and document edge runtime limitations
1 parent 927aadf commit cc5a23f

7 files changed

Lines changed: 36 additions & 9 deletions

File tree

docs/src/content/guides/ssr-images.md

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -187,10 +187,10 @@ These examples are rendered live from the API endpoints in this project.
187187
```
188188

189189
```html
190-
<img src="/api/charts/line?background=white" />
190+
<img src="/api/charts/line" />
191191
```
192192

193-
![Line chart](/api/charts/line?background=white)
193+
![Line chart](/api/charts/line)
194194

195195
### Bar chart
196196

@@ -215,10 +215,10 @@ These examples are rendered live from the API endpoints in this project.
215215
```
216216

217217
```html
218-
<img src="/api/charts/bar?background=white" />
218+
<img src="/api/charts/bar" />
219219
```
220220

221-
![Bar chart](/api/charts/bar?background=white)
221+
![Bar chart](/api/charts/bar)
222222

223223
### Area chart (multi-series)
224224

@@ -245,10 +245,10 @@ These examples are rendered live from the API endpoints in this project.
245245
```
246246

247247
```html
248-
<img src="/api/charts/area?background=white" />
248+
<img src="/api/charts/area" />
249249
```
250250

251-
![Area chart](/api/charts/area?background=white)
251+
![Area chart](/api/charts/area)
252252

253253
### Scatter chart
254254

@@ -271,10 +271,10 @@ These examples are rendered live from the API endpoints in this project.
271271
```
272272

273273
```html
274-
<img src="/api/charts/scatter?background=white" />
274+
<img src="/api/charts/scatter" />
275275
```
276276

277-
![Scatter chart](/api/charts/scatter?background=white)
277+
![Scatter chart](/api/charts/scatter)
278278

279279
## Supported components
280280

@@ -334,6 +334,23 @@ const buffer = renderChart(MyChart, {
334334
});
335335
```
336336

337+
### Cloudflare and edge runtimes
338+
339+
Server-side chart rendering requires a **native Node.js canvas library** such as `@napi-rs/canvas`, `node-canvas`, or `skia-canvas`. These are native addons that do not run on edge runtimes like Cloudflare Workers.
340+
341+
If you deploy to Cloudflare Pages (or similar edge platforms), **prerender your chart endpoints** so the images are generated at build time:
342+
343+
```ts
344+
// +server.ts
345+
export const prerender = true;
346+
347+
export const GET: RequestHandler = async ({ url }) => {
348+
return renderChartResponse({ component: MyChart, props: { data }, url });
349+
};
350+
```
351+
352+
Prerendered endpoints become static files served directly from the CDN — no server-side canvas library needed at runtime. Note that query parameters (like `?width=1200`) are not available for prerendered routes, so bake any defaults into the endpoint code.
353+
337354
### Inline styles only
338355

339356
Since there is no DOM or CSS engine on the server, use inline style props (`fill`, `stroke`, `strokeWidth`, etc.) instead of CSS classes or Tailwind utilities.

docs/src/routes/api/charts/area/+server.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { renderChartResponse } from '../renderChartEndpoint.js';
22
import type { RequestHandler } from './$types';
33
import AreaChart from './AreaChart.svelte';
44

5+
export const prerender = true;
6+
57
const data = Array.from({ length: 50 }, (_, i) => ({
68
date: i,
79
value: 50 + 30 * Math.sin(i / 5) + 10 * Math.cos(i / 3),

docs/src/routes/api/charts/bar/+server.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { renderChartResponse } from '../renderChartEndpoint.js';
22
import type { RequestHandler } from './$types';
33
import BarChart from './BarChart.svelte';
44

5+
export const prerender = true;
6+
57
const data = [
68
{ category: 'A', value: 28 },
79
{ category: 'B', value: 55 },

docs/src/routes/api/charts/geo/+server.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import { renderChartResponse } from '../renderChartEndpoint.js';
55
import type { RequestHandler } from './$types';
66
import GeoChart from './GeoChart.svelte';
77

8+
export const prerender = true;
9+
810
let cachedStates: ReturnType<typeof feature> | null = null;
911

1012
async function getStates(fetchFn: typeof fetch) {

docs/src/routes/api/charts/line/+server.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { renderChartResponse } from '../renderChartEndpoint.js';
22
import type { RequestHandler } from './$types';
33
import LineChart from './LineChart.svelte';
44

5+
export const prerender = true;
6+
57
const data = Array.from({ length: 50 }, (_, i) => ({
68
date: i,
79
value: 50 + 30 * Math.sin(i / 5) + 10 * Math.cos(i / 3)

docs/src/routes/api/charts/renderChartEndpoint.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export function renderChartResponse({
2525
const width = Number(url.searchParams.get('width') ?? 800);
2626
const height = Number(url.searchParams.get('height') ?? 400);
2727
const format = url.searchParams.get('format') === 'jpeg' ? 'jpeg' : 'png';
28-
const background = url.searchParams.get('background') ?? undefined;
28+
const background = url.searchParams.get('background') ?? 'white';
2929

3030
const buffer = renderChart(component, {
3131
width,

docs/src/routes/api/charts/scatter/+server.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { renderChartResponse } from '../renderChartEndpoint.js';
22
import type { RequestHandler } from './$types';
33
import ScatterChart from './ScatterChart.svelte';
44

5+
export const prerender = true;
6+
57
// Generate clustered scatter data
68
const random = (seed: number) => {
79
const x = Math.sin(seed) * 10000;

0 commit comments

Comments
 (0)