npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@pluxel/echarts

v1.0.0

Published

Official server-side Apache ECharts capability for Pluxel plugins

Readme

@pluxel/echarts

@pluxel/echarts uses Apache ECharts 6 and @pluxel/canvas to render charts on the server. All renders run through Pluxel's root-owned shared worker pool, so layout, text measurement, ZRender flush and native encoding do not occupy the main event loop. The host still performs a cooperative option-budget walk and bounded worker transport serialization. Canvas owns resource limits; Fonts supplies the managed registry, provider-wide default family, and provider-owned Fonts selection Attachment.

import { EChartsPlugin } from '@pluxel/echarts'
import { BasePlugin, Plugin } from '@pluxel/runtime'

@Plugin()
export class ReportsPlugin extends BasePlugin {
	constructor(private readonly charts: EChartsPlugin) {
		super()
	}

	async renderSales(): Promise<Buffer> {
		const result = await this.charts.render({
			width: 1200,
			height: 630,
			option: {
				xAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed'] },
				yAxis: { type: 'value' },
				series: [{ type: 'bar', data: [120, 200, 150] }],
			},
		})
		return result.data
	}
}

The host catalog contains [FontsPlugin, CanvasPlugin, EChartsPlugin, ReportsPlugin]. render() is worker-only and uses the host-wide ctx.workers thread/queue budget. The worker reconstructs the bounded @pluxel/canvas/worker adapter from canvas.workerSnapshot, initializes ECharts in SSR mode, waits for tracked images, flushes, encodes, and disposes the instance in finally. It then closes the caller-owned Canvas adapter, which cancels queued image work and waits already-submitted native decodes before the handler releases its Worker. ECharts does not initialize another CanvasPlugin or directly depend on the native binding. The option graph is borrowed without mutation until the render settles. Bytes/value/depth budgets run only after shared fair admission, so queue rejection does not first walk the graph; they bound dispatch serialization, including cooperative chunks for one large string, and the worker rewrites only its private transport clone. PNG is the default; JPEG/WebP and DPR are explicit options.

Themes and fonts

const theme = this.charts.registerTheme({
	name: 'reports',
	theme: {
		color: ['#2563eb', '#16a34a'],
		backgroundColor: '#ffffff',
	},
})

await this.charts.render({ width: 800, height: 400, option, theme: theme.name })
theme.dispose() // optional; caller stop also removes it

Named themes are JSON values stored in a caller-owned Pluxel registry. They are deliberately not written to ECharts' process-global registerTheme() table, which has no unregister API. Different callers may reuse the same local name, and caller stop/replacement deactivates its registrations. Inline theme objects and ECharts' built-in default/dark names are also accepted. Theme bytes, value count and nesting depth are bounded before the JSON snapshot is retained. Named registrations also share provider-wide retained count/byte ceilings; dispose and caller stop return that capacity.

When neither the option nor theme explicitly supplies textStyle.fontFamily, each render injects the current FontsPlugin.defaultFont.cssFamily. Therefore provider preference changes affect subsequent renders without rewriting registered themes. The ECharts plugin detail places the provider-owned Fonts selection Attachment; the canonical FontsPlugin page alone uploads and removes fonts. The single managed collection remains server-process-only and survives Canvas/ECharts consumer stops.

Images and outbound policy

Data URL image strings in plain image fields and image://data: values are replaced with short render-local keys before they reach ZRender, decoded through the Canvas worker adapter, and subject to per-source bytes, distinct-source count, aggregate source bytes, aggregate decoded pixels, and Canvas byte/dimension budgets. The trusted placeholder is decoded in place once; a source is not decoded into a temporary Image and then decoded again through src. Ordinary text beginning with data: is left untouched. A render-local failure aborts the other image tasks and suppresses late callbacks. Canvas worker decode admission defaults to one per adapter, while the Runtime worker pool supplies outer parallelism; the two limits are local admission rather than ownership of the process-wide libuv pool. A native Image, formatter function, accessor, class instance or shared mutable buffer cannot cross the declarative worker boundary and is rejected without an inline fallback.

Encoded raster bytes are checked against maxOutputBytes inside the worker before result transport; the ceiling limits returned data but cannot undo encoder work already completed.

HTTP(S) URLs and server file paths are rejected. Fetch bytes first through an outbound HTTP capability, enforce its download budget, and encode a bounded data URL for the declarative option. Native Canvas/Image objects cannot cross this worker-only boundary. This keeps redirect, authentication, proxy, retry, origin, and cancellation policy outside a drawing library.

See DESIGN.md for global-state and concurrency invariants and docs/plugins/rendering/echarts.md for the full author path.