Conversation
built with Refined Cloudflare Pages Action⚡ Cloudflare Pages Deployment
|
commit: |
🦋 Changeset detectedLatest commit: 753b19b The changes in this PR will be included in the next version bump. This PR includes no changesetsWhen changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Hey, @techniq. I have a question: When are you planning to merge this PR so we can finally get the Svelte 5 support? 🤗 |
|
Hey @HicaroD, thanks for the kind words 🫶. Sorry, I don't have a rough release date set yet. There are a good number of improvements I would like to include in With that said, you 100% can use it today via I could see pushing some items to Related: I also need to migrate Svelte UX fully over to Svelte 5 (it's Svelte 3-5 compat with Svelte 3/4 state/syntax). Both libraries have already been migrated to Tailwind 4, but the move to Svelte 5 state runes/snippets and regressions checking will take some concentrated efforts and time. I don't know how close I'll try to sync their release schedules though (and the benefit of having |
|
All the examples give 500 errors on https://next.layerchart.com/ |
@cycle4passion Odd... working here Maybe try a hard refresh? Which browser? |
|
mobile only, does not work in arc (chromium), native chrome, or Safari browser. |
The `{#await}` block doesn't anchor a remote `query` to SSR's hydratable serialization, so on hydration the client threw `hydratable_missing_but_required` looking for `getStats/`. Switch to the `query.loading`/`error`/`current` pattern, which is the supported path for remote queries and also avoids the async-mode `<svelte:boundary>` commit that triggered a "Batch has scheduled roots" invariant.
* Initialize bundle analyzer package * update bundle baseline
- Sum entry chunk + all chunks reachable via static imports (so the reported size reflects true up-front cost; lazy chunks excluded) - Add `--visualize` flag (and `bundle:visualize` script) that emits an interactive treemap HTML per scenario via `rollup-plugin-visualizer` - Regenerate `latest.json` baseline with the new methodology
* Initialize bundle analyzer package
* update bundle baseline
* Prepare ChartChildren and Chart for tree-shaking
- Add `"sideEffects": ["**/*.css"]` to layerchart/package.json so downstream bundlers can prune unused barrel re-exports
- Convert ChartChildren's value imports of components only referenced in `ComponentProps<typeof X>` to `import type` (Area, Arc, Bars, BrushContext, Group, Line, Pie, Spline, TooltipContext)
- Inline `geoFitObjectTransform` into Chart.svelte to drop the static import edge through `$lib/utils/geo.js` (which transitively imports d3-geo)
No visible change in the bundle analyzer (it already does aggressive treeshaking), but unlocks the dynamic-import refactor in the next commit and protects consumers whose bundlers tree-shake less aggressively.
* Lazy-load conditionally-rendered components in Chart
Convert statically-imported components to `{#await import(...)}` so they only ship to users who opt in via the corresponding prop:
- ChartChildren: ChartAnnotations (when annotations.length > 0), DefaultTooltip (tooltipContext truthy), Labels, Legend, Points
- TooltipContext: Voronoi (mode === 'voronoi'), Arc (radial bounds/band)
Voronoi alone removes d3-geo-voronoi and its transitive d3-geo from the always-loaded bundle.
Update the bundle analyzer to sum the entry chunk plus all chunks reachable via static imports (lazy chunks excluded), so the reported size reflects up-front cost rather than total feature surface.
Result: `core` (`Chart` + `Svg`) drops 154.94 → 109.95 KB gz (-29%). Comparable savings on every scenario except `all` (which exercises every lazy path).
* Add `pnpm bundle:visualize` to generate treemaps using rollup-plugin-visualizer
* Fix BarChart legend toggle test for lazy-loaded Legend
The test queried `.lc-legend-swatch-button` synchronously, but `Legend` is now dynamically imported inside `ChartChildren` and isn't in the DOM until the chunk resolves. Wrap the query in `vi.waitFor` so the test waits for the buttons to mount before clicking.
* Fix analyzer footgun: don't overwrite latest.json on filtered runs
A filtered run (e.g. `pnpm bundle:visualize -- core`) was overwriting `bundle-reports/latest.json` with just the filtered scenarios, causing the PR comparison comment to show "0 KB" for every scenario the filtered run didn't cover. Now `latest.json` is only updated when no `--components`, scenario, or component filters are passed; filtered runs still get a timestamped report. Also regenerate the full baseline against the current lazy-loaded code.
* Fix CI test failure by avoiding tooltip namespace barrel in DefaultTooltip
DefaultTooltip is dynamically imported from ChartChildren. It was using `import * as Tooltip from '../tooltip/index.js'`, which dragged the entire tooltip barrel — including TooltipContext.svelte (already in the static graph via Chart.svelte) — into its lazy chunk. Under CI's resource-constrained dev server this broke the DefaultTooltip browser test ("Failed to fetch dynamically imported module"). Replace the namespace import with explicit named imports of just the 5 components actually used (no Context). The local `const Tooltip = { Root, Header, List, Item, Separator }` keeps the existing template syntax (`<Tooltip.Root>`, etc.) unchanged. Bonus: tightens tree-shaking — `all` scenario drops ~3 KB gz.
* Revert DefaultTooltip lazy-load to fix vitest-browser CI test
The dynamic import of `DefaultTooltip` from `ChartChildren` caused a CI-only "Failed to fetch dynamically imported module" failure in `DefaultTooltip.svelte.test.ts`. Local tests passed; only the Linux/playwright runner reproduced. Switching the inner `import * as Tooltip` namespace to named imports (commit 7e5d6e7) didn't help. The savings were small (~5 KB gz on `core`) and not worth the test instability — the other lazy-loads (Voronoi, Arc, ChartAnnotations, Labels, Legend, Points) remain. Net Phase 2 gain on `core` is now -39 KB gz (-25%) instead of -45 KB gz (-29%).
* Revert ChartChildren lazy-loads; keep TooltipContext lazy-loads
The DefaultTooltip vitest-browser test still failed in CI ("Failed to fetch dynamically imported module") even after reverting just DefaultTooltip's lazy-load and after switching the inner namespace import to named imports. Rather than continue narrowing, revert all 4 ChartChildren lazy-loads (Labels, Legend, Points, ChartAnnotations). The TooltipContext lazy-loads (Voronoi, Arc) stay — they're the biggest win (~17 KB gz on core from removing d3-geo-voronoi + d3-geo from the static graph) and aren't in the test failure path. Net Phase 2 gain on `core` is now -17 KB gz (-11%).
* Switch ChartChildren lazy-loads from `{#await}` to `$effect`
The `{#await import('./X.svelte')}` template pattern broke `DefaultTooltip.svelte.test.ts` in CI ("Failed to fetch dynamically imported module" on the test file). Local tests passed; only the Linux/playwright runner reproduced. Move the dynamic imports back into `$effect` blocks (script-side `import()`), which Vite/vitest-browser appears to handle differently. Same chunks, same bundle savings, but the dynamic imports live in regular JS rather than Svelte template syntax. TooltipContext keeps `{#await}` for Voronoi/Arc — those weren't in the test failure path. Net Phase 2 gain on `core` recovered to -40 KB gz (-25%).
* Refactor lazy-loading to a `<Lazy>` wrapper with prop-spread + `then` snippet
Replace per-component `$state`/`$effect`/conditional-render boilerplate in ChartChildren with a generic `<Lazy>` component that takes a `load` factory and either spreads remaining props to the loaded component (single-render case: ChartAnnotations, Legend) or passes it via a `then` snippet (loop case: Points, Labels). Conditional gating uses standard `{#if}` outside `<Lazy>` rather than a `when` prop. The snippet is named `then` (not `children`) to avoid collisions with loaded components that have their own `children` prop. Same bundle behavior and CI-friendly `$effect`-under-the-hood as the previous explicit pattern; ~half the lines per lazy-load.
* Use `{#await import(...)}` for lazy-loads; remove `<Lazy>` wrapper
Now that `optimizeDeps.include: ['d3-interpolate']` prevents the mid-test Vite reload (the actual cause of the CI flake), the cleaner inline `{#await import('./X.svelte') then { default: X }}` pattern works fine in CI. Revert ChartChildren back to that pattern, matching what TooltipContext already does. Remove `Lazy.svelte` since it's no longer needed. Same chunks, same ~25% savings on `core` (115.60 KB gz).
* Add `build` script alias so CI's `build:packages` actually builds layerchart
The bundle analysis CI workflow runs `pnpm build:packages` (which calls `pnpm --filter './packages/*' build`) before `pnpm bundle:analyze`. layerchart only had a `package` script (svelte-package convention), no `build`, so the filter call did nothing in CI — the analyzer ran against an empty `dist/` and produced 0-byte sizes for every scenario. That's why the PR comment showed "0.00 KB" for "New". Add a `build` alias for `svelte-package` (kept alongside existing `package` for back-compat) so CI's existing build step now actually rebuilds layerchart's `dist/`.
* Add percentage change to bundle analysis PR comment
The script already computed `sizePercent` and `gzipSizePercent`; now display them inline in the Change column alongside the raw KB deltas (e.g. `-160.00 KB (-25.1%)`). Easier to scan relative impact across scenarios than raw byte counts alone. Same for the Individual Components table.
* Group bundle analysis scenarios in PR comment by category
Add a `group` field to scenarios (Foundation, Cartesian charts, Geo, Hierarchy, Graph / network, Worst case) and render the PR comment with one sub-table per group instead of one alphabetized list. Reorder `define-scenarios.ts` to put `core` first and scenarios within their category. Remove the alphabetical sort in `analyzeChanges` so the comment preserves the natural order.
* Move heavy-dep components into sub-path exports
Remove from root `layerchart`: `Geo*` + `Graticule` + `TileImage`, `Tree`/`Treemap`/`Pack`/`Partition`, `ForceSimulation`, `Dagre`/`Sankey`/`Chord`/`Ribbon`. Each group now lives in its own folder + sub-path entry: `layerchart/geo`, `layerchart/hierarchy`, `layerchart/force`, `layerchart/graph`.
Defends against bundlers that don't tree-shake the root barrel cleanly — `@dagrejs/dagre` (~22 KB), `d3-geo` (~15 KB), `d3-force` (~7 KB), `d3-hierarchy` (~6 KB), `d3-sankey` (~6 KB), and `d3-chord` (~2 KB) are now reachable only via opt-in imports. Per-scenario bundle sizes are unchanged for already-good consumers; the worst-case `all` scenario drops 241.8 → 235.5 KB gz.
`Voronoi`/`Hull` stay at root (already lazy via `TooltipContext`). `Contour`/`Density`/`Raster`/`BoxPlot`/`Violin`/`Threshold` also stay (not category-specific). High-level charts (`LineChart`, `BarChart`, etc.) remain at root.
Breaking: imports for the moved components must move to the new sub-paths.
* Lazy-load opt-in features in core path
Three components that everyone pays for in `core` today, but only some users actually need:
- `Spline` in `Grid` (radial linear grid lines only — non-radial users never render it)
- `Bar` in `Highlight` (only when user sets `bar` prop, default `false`)
- `BrushContext` in `Chart` (only when user sets `brush` prop, default `undefined`) — required splitting the inner `<TooltipContext>` tree across the brush/no-brush branches; brush tests now wait for the lazy chunk via a new `awaitBrushReady` helper
Saves ~4 KB gz on `core` (115.60 → 111.31 KB) and similar on every cartesian/geo/graph/hierarchy scenario. ~28% total reduction on `core` vs the pre-Phase-1 baseline.
Also switch `@layerstack/svelte-actions` imports from the barrel to sub-paths (`/styles`, `/portal`). No bundle effect since tree-shaking already stripped the unused `popover.js`, but it stops the Svelte REPL/CDN from eagerly fetching `@floating-ui/dom` (popover's transitive dep) when users load `layerchart` from a CDN.
* add changeset for lazy loading opt-in features (brush, radial spline, etc)
* lazy load d3-quadtree and DefaultTooltip based on usage
* Render chart subtree during BrushContext lazy load
The previous structure put `<TooltipContext>` + `<ChartChildren>` *inside* the `{#await import('./BrushContext.svelte')}` block, so on slow networks the entire chart was blocked on the chunk fetch (~300-1000ms on Fast 4G). Move the same subtree into the `{#await}`'s pending branch as well so the chart paints immediately; the `{:then}` branch then re-mounts it inside `BrushContext` once the chunk arrives.
Trade-off: brief one-time re-mount of `TooltipContext` + `ChartChildren` (~50ms) when the chunk lands. Acceptable because it happens before any user interaction (no tooltip/series state to lose) and brush is opt-in. Bundle savings preserved (core +0.1 KB from the duplicated template, since the actual modules are deduped).
The other lazy-load sites (`Voronoi`/`Arc` in `TooltipContext`, `DefaultTooltip`, `Bar`, `Points`/`Labels`/`Legend`/`ChartAnnotations` in `ChartChildren`, `Spline` in `Grid`) don't need the same treatment — none of them block visible chart content from rendering.
Co-authored-by: github-actions[bot] <action@github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* split Circle.svelte into 3 layer-specific components (Circle.svg.svelte, etc) along with CircleState (Circle.shared.svelte.ts). Keep Circle.svelte and delegate to underlying type
* split Text.svelte into 3 layer-specific components
* Organize into component directories
* split Rect, Line, and Path into 3 layer-specific components
* split Ellipse, Polygon, Group, Image, ClipPath, Pattern, LinearGradient, and RadialGradient into 3 layer-specific components
* Add changeset for per-layer primitive
* split Axis into 3 layer-specific components
* Add full-chart layer examples (to monitor progress)
* split Grid and Rule into 3 layer-specific components
* split Chart and ChartChildren into 3 layer-specific components, and alias Layer based on layer type (Layer within layerchart/svg => Svg)
* refine bundle scenarios
* refine bundle scenarios
* Add more foundation examples
Co-authored-by: Copilot <copilot@github.com>
* improve bundle comment
* split Highlight, ChartClipPath, RectClipPath into 3 layer-specific components
* split Arc, Area, and Spline into 3 layer-specific components
* split ArcLabel, Bar, Bars, Labels, Pie, and Points into 3 layer-specific components
* split Frame, Cell, Threshold, AnnotationLine, AnnotationPoint, and Trail into 3 layer-specific components
* split AnnotationRange, CircleClipPath, Vector, Link, Hull, Density, and Calendar into 3 layer-specific components
* split BoxPlot, Violin, Raster, Month, Contour, and Voronoi into 3 layer-specific components
* split geo components (GeoPath, GeoSpline, etc) into 3 layer-specific components
* split Ribbon into 3 layer-specific components. Re-export all layout/helper components
* split high-level charts (BarChart, LineChart, etc) into 3 layer-specific components. Re-export all layout/helper components
* update changeset and docs
* Update bundle size PR comment with collapsible sections
* Remove `Svg` from core (just Chart)
* Split `Foundation` scenarios into `Core (agnostic)` and `Core (layer-specific)`
* update bundle report
* Lazy load transform context (and only when used) similar to brush context
* Add ChartCore. Fix TransformContext test
* update bundle sizes in docs
* move core section above base
* Fix primitive fill/stroke for canvas primitives
* fix(Text): Render on `<Svg>` layer when only one of `x`/`y` is set
The static-mode render guard required both `x` and `y` to be explicit, so
`<Text y={-6}>` inside a positioned `<Group>` (e.g. tooltip labels in the
GeoPoint world-capitals example) was skipped on the Svg layer — Canvas
worked because it doesn't gate on coordinate validity.
Change `&&` to `||` so Text renders when either coordinate is set; the
missing one falls through to the existing `motionX`/`motionY` default of 0,
matching SVG's natural "missing coord = 0" behavior and the Canvas variant.
* fix components missing html impls (Calendar, Bars, Annotation*, etc)
* Fix Text within group
---------
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: github-actions[bot] <action@github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* perf: Skip motion container allocation when `motion` prop is `undefined` * perf: Skip mark-info `$effect` for pixel-mode primitives * perf: Reduce per-tick reactive overhead in `Path` / `Link` (force-simulation graphs) * fix(Arc, RectClipPath, ChartClipPath): Restore on-mount tween animations * Force SVG for lattice example to verify delegation perf issue * Revert lattice svg force * Improve bundle size warnings * sort bundle scenarios by size desc * sort warnings by change desc * Revert "perf: Skip motion container allocation when `motion` prop is `undefined`" This reverts b45f47a. Empirical measurements on the lattice (n=20, 760 links) and tree force-simulation examples showed the call-site gating produced no measurable FPS difference vs. an unmodified `createMotion` — the fast path at `motion.svelte.ts:197-213` (passthrough returned when `motionProp === undefined`) already covers the no-motion case. | Example | Phase | Before | After (revert) | |----------|-------------|-----------|---------------:| | Lattice | steady sim | 6.46-6.53 | 6.52-6.58 | | Tree | active sim | 16.88-17.28 | 17.46-17.51 | The 728-line, 13-file diff added per-call-site gates and null-check fallbacks for an optimization that was already happening one layer down. Reverting restores the simpler unconditional construction. The Path.shared.svelte.ts merge keeps ee6b332's `#getPathData` hot-path getter (which is independent of the motion-alloc question) and switches the initial-pathData resolution to `resolvePathData()` to handle the polymorphic `string | () => string` form added by that commit. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(SeriesState): Avoid `derived_inert` crash when chart unmounts under a `<svelte:boundary>` --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <action@github.com>
Co-authored-by: github-actions[bot] <action@github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…s` is metadata-only


No description provided.