Skip to content

[Size] motion() bundles every motion feature (about 22 KB gzip) #205

Open

Description

@toomingos

motion is a single exported function from motion.ts:757 to the end of the file (line 4177). Features a chart may never use are closed over inside it, so a bundler cannot drop them:

  • rolling path morph (resolveRollingPathPlan, motion-path.js)
  • rect corner morph (rectCornerRadiiPath, renderer-rect.js)
  • focus-guide layer markup (renderFocusGuideLayer, svg-renderer.js)
  • mark state scenes (resolveMarkStateScene)
  • the tooltip spring (createChartSpring, spring.js)

ChartMotionOptions (initial, transition, respectReducedMotion, resize) has nothing that selects features.

Numbers

esbuild 0.28, minify, tree-shake, react external, gzip -9. Each row replaces the named dist file with an empty stub (size only).

Entry Total gzip Without motion.js
PieChart 56,993 B -22,182 B (39%)
LineChart 107,134 B -22,658 B
SunburstChart 70,217 B -22,804 B

Only about 3.3 KB of this is in separate modules (motion-path 966 B, spring 542 B, svg-renderer 1,489 B, renderer-rect 294 B). The other ~19 KB is inside the function body.

A chart that never calls motion() does not pay this. A pie that only needs an entrance tween does.

Proposal

Make the engines opt-in, for example motion({ path: rollingPath(), focusGuides: guideMotion() }) with each engine in its own subpath module. Or split the entrance and settle core from path morph, rect morph, focus guides and the tooltip spring.

Not the same as #153 (closed), which shared runtime code across entries. Checked against 57774e14a1a86081eddb3a23523724a40da05640 (v1.1.0).

Activity

  1. changed the title [-]`motion()` is one function, so every chart that uses it bundles every motion feature (about 22 KB gzip)[/-] [+][Size] `motion()` bundles every motion feature (about 22 KB gzip)[/+] on Oct 13, 2026
  2. tannerlinsley commented on Oct 14, 2026

    @tannerlinsley
    Member

    Thanks for the size breakdown, @toomingos. #232 adds a separate motionLite() import from @tanstack/charts/motion/lite, leaving existing motion() behavior unchanged.

    The new entry measures 9.541 kB gzip versus 23.192 kB for full motion. In the same bar-chart consumer it reduces gzip size from 59.250 to 43.752 kB. These are real builds without stubbing modules, but they offer different features: the smaller renderer provides whole-chart fade entrance and basic keyed SVG updates, without springs, rolling paths, per-mark timing, or interpolated interaction points. The reference documents those limits.

    All 114 existing consumer bundles are byte-identical, required local validation and maintained builds pass, and browser checks cover Chromium, Firefox, and WebKit. The PR is waiting for CI and review, so this is not published yet. I'll keep this issue open through release verification.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions