Strip unused stats internals from shipped bundle (~580 B gz / bundle)#3744
Strip unused stats internals from shipped bundle (~580 B gz / bundle)#3744mattgperry wants to merge 1 commit into
Conversation
The stats module shipped per-frame counters and a reportStats() summariser that no external consumer reads — only the HTML projection perf tests in dev/html use statsBuffer (and only the layoutProjection metrics). Removed: - record() per-frame callback + frame.postRender scheduling - summarise(), mean(), msToFps(), reportStats(), Summary/StatsSummary types - activeAnimations counters + mutations in JSAnimation, start-waapi-animation, create-projection-node (mainThread/waapi/layout) — nothing reads them - stepName param + numCalls in render-step (per-step counter pushes); nothing outside the removed summariser consumed them - frameloop / animations shape from the stats buffer; recordStats now only initialises layoutProjection Kept (HTML projection harness still uses these via window.Projection): - recordStats() — flips statsBuffer into recording mode for layoutProjection - statsBuffer + addProjectionMetrics — fed by create-projection-node gates - The 4 `if (statsBuffer.value)` / `if (statsBuffer.addProjectionMetrics)` gates in create-projection-node Bundle deltas (gzipped): - motion-dom.js: 38921 -> 38342 (-579 B) - framer-motion.js: 60694 -> 60090 (-604 B) - dom.js: 44678 -> 44091 (-587 B) - motion-dom.dev.js: 90813 -> 89959 (-854 B) - stats/index.mjs: 997 -> 350 (-647 B) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Greptile SummaryThis PR strips unused stats infrastructure from the shipped bundle by removing the
Confidence Score: 5/5Clean dead-code removal with no behavioral changes to the animation engine; the only retained path (layoutProjection metrics) is unchanged. Every removed call site had a single purpose — incrementing or reporting counters that nothing outside the dev test harness ever read. The one live consumer (HTML projection perf tests) relies solely on the layoutProjection arrays and the addProjectionMetrics callback, both of which are preserved verbatim. The onStop removal in create-projection-node is safe because that handler exclusively decremented activeAnimations.layout. Tests are updated and passing. No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["recordStats()"] --> B["statsBuffer.value = { layoutProjection: {...} }"]
B --> C["statsBuffer.addProjectionMetrics = callback"]
D["create-projection-node\n(4 guarded sites)"] -->|"if statsBuffer.addProjectionMetrics"| E["addProjectionMetrics(metrics)"]
E --> F["layoutProjection.nodes.push()\ncalculatedTargetDeltas.push()\ncalculatedProjections.push()"]
G["HTML test harness\nscript-assert.js"] -->|"reads"| H["statsBuffer.value.layoutProjection\n.nodes / .calculatedTargetDeltas / .calculatedProjections"]
subgraph REMOVED ["Removed from bundle"]
R1["record() per-frame callback"]
R2["activeAnimations counters"]
R3["reportStats / summarise / mean / msToFps"]
R4["frameloop + animations shapes"]
R5["numCalls + stepName in render-step"]
end
style REMOVED fill:#fee2e2,stroke:#ef4444
Reviews (1): Last reviewed commit: "Strip unused stats internals from shippe..." | Re-trigger Greptile |
Why
The runtime stats system shipped:
record()callback scheduled everypostRenderframe,reportStats()summariser (summarise,mean,msToFps, FPSconversion),
activeAnimations.mainThread/waapi/layoutcounters mutated by everyJS animation construct/teardown, every WAAPI start/finish, and the
layout-animation lifecycle,
render-step,Summary/StatsSummary/FrameStatstype exports.Search across the monorepo and the public-debug entries (
framer-motion/debug,framer-motion/projection) shows the only live consumer isdev/html/src/imports/script-assert.js, which readsstatsBuffer.value.layoutProjection.{nodes,calculatedTargetDeltas,calculatedProjections}to make assertions in the HTML projection perf tests (perf-single,perf-neighbours,perf-parent-child,perf-shared-deep, etc.).It calls
recordStats()to flip the flag, then reads the projection counters directly. It never calls the returnedreportStats, never touchesframeloop/animationsshape, never readsactiveAnimations.So everything else was shipping to users for no consumer. This strip keeps that test harness functional today while removing the rest from the bundle.
What stayed
recordStats()— now just initialisesstatsBuffer.value.layoutProjection = {...}and installsaddProjectionMetrics. No frame is scheduled.statsBuffer+addProjectionMetricscallback.if (statsBuffer.value)/if (statsBuffer.addProjectionMetrics)gates increate-projection-nodethat push projection counts.recordStats/statsBufferfromframer-motion/projection(the entry the HTML harness reaches viawindow.Projection).What went
record()per-frame callback +frame.postRender(record, true)frameloop.rateandanimations.*arrays nothing readsreportStats(),summarise,summariseAll,mean,msToFps, FPS conversionclearStatsBuffer(kept only as the internal narrowing trick)reportStatsactiveAnimations+ counter increments inJSAnimation,start-waapi-animation,create-projection-nodeanimations.*arrays that nothing readsstepNameparam +numCalls+ the stats push inrender-stepframeloop.*arraysallowKeepAlive ? key : undefinedinbatcherframeloop+animationsshape from the stats bufferlayoutProjectionis readSummary,StatsSummary,FrameStats,Stats<T>,StatsBuffertypes + the barrel re-export ofanimation-countpackages/motion-dom/src/stats/animation-count.tsBundle deltas (gzipped,
gzip -9)motion-dom/dist/motion-dom.jsmotion-dom/dist/motion-dom.dev.jsmotion-dom/dist/cjs/index.jsmotion-dom/dist/es/stats/index.mjsframer-motion/dist/framer-motion.jsframer-motion/dist/dom.jsframer-motion/dist/dom-mini.js~580 B gz off every user-facing bundle that includes the animation engine.
Public API
recordStatsis still exported (HTML test relies on it viaframer-motion/projection) but its signature narrowed: it no longer returns areportStatscallback. Anyone in the wild who was callingconst stop = recordStats(); stop()to get a summary will need to switch — but the prior behaviour summarised data nobody else was collecting, so it's hard to imagine a real consumer.The
Summary/StatsSummary/FrameStatstypes are removed from the public type surface.Follow-up
Future change should move the HTML projection harness off
statsBuffer(e.g. expose a per-node hook to countpropagateDirtyNodes/resolveTargetDelta/calcProjectioninvocations) so the 4 remainingstatsBuffergates increate-projection-nodecan be dropped too — at which pointstats/can be deleted entirely. Out of scope here to keep the diff focused.Supersedes
#3742 — that PR refactored
summarise()to dedupe its 15 call sites; this PR removessummarise()altogether. Close #3742 when this lands.Verification
yarn buildclean.yarn test— 797 passed, 7 skipped, 0 failed (incl. the rewritten projection-metric Jest test inmotion-dom/src/stats/__tests__/index.test.ts).recordStats()still initialisesstatsBuffer.value.layoutProjection, the 4 projection-node gates still push, andscript-assert.js'scheckFramereads the same array shape it did before.🤖 Generated with Claude Code