Skip to content

perf(web): dedupe framer-motion onto the version motion already ships - #3533

Merged
richiemcilroy merged 2 commits into
mainfrom
perf/dashboard-dedupe-framer-motion
Oct 29, 2026
Merged

richiemcilroy merged 2 commits into
mainfrom
perf/dashboard-dedupe-framer-motion

Conversation

@richiemcilroy

@richiemcilroy richiemcilroy commented Oct 29, 2026 •

Copy link
Copy Markdown
Member

The web app shipped two builds of the animation library on every dashboard route. apps/web pinned framer-motion@^11, while motion@12 (imported as motion/react elsewhere in the app) brings its own nested framer-motion@12. Turbopack bundles both, so every dashboard page loaded framer-motion 11 and framer-motion 12 together.

This PR pins apps/web to framer-motion@^12.42.2, the exact version motion already depends on. Bun then resolves a single copy, and the bun.lock diff is only the motion entries:

- "framer-motion": ["framer-motion@11.18.2", ...
+ "framer-motion": ["framer-motion@12.42.2", ...
- "motion-dom": ["motion-dom@11.18.1", ...
+ "motion-dom": ["motion-dom@12.42.2", ...
- "motion/framer-motion": ["framer-motion@12.42.2", ...
  • The app uses only motion, AnimatePresence, Variants and MotionProp from framer-motion. Motion's upgrade guide says: "There are no breaking changes in Motion for React in version 12."
  • v12's types are stricter about ease. The first commit annotates five variant objects as Variants (type only). In Navbar/Items.tsx:220 it changes type: "easeInOut" (not a valid generator type) to ease: "easeInOut". That motion.div has no animate, initial, layout or gesture props, so its transition is never read on either version.
  • No component source changes beyond those types.

Numbers

Initial JS per route, gzipped (route entry chunks plus root main files, from the build manifests). Measured from a clean install; an in-place bun install leaves the old nested copy in node_modules/motion/node_modules and shows no saving.

Route main this PR
/dashboard/caps 962.3 KB 923.1 KB
/dashboard/folder/[id] 965.5 KB 926.3 KB
/dashboard/spaces/[spaceId] 946.6 KB 907.3 KB
/dashboard/settings/organization 953.5 KB 914.2 KB
every other dashboard route 893 to 917 KB 39.2 KB less
/login, /signup, /verify-otp 342.5 / 342.6 / 333.0 KB 348.4 / 348.4 / 338.1 KB
/, /pricing, /download, /s/[videoId] unchanged

The auth pages only ever loaded v11. v12 on its own is 5.5 to 5.9 KB larger, and they need layout animations, so they can't drop to a lighter feature set.

Runtime: production builds on a Mac mini against the same seeded database and storage, both servers restarted and warmed before the run. Headless Chromium, cold load, median of 9 runs, base and head alternating. Throttled is 4x CPU and 10 Mbps / 40 ms.

Page Profile Metric main this PR
/dashboard/caps throttled hydrated 1,367 ms 1,334 ms
/dashboard/settings/organization throttled hydrated 1,340 ms 1,289 ms
/dashboard/caps fast hydrated 231 ms 227 ms
/dashboard/caps any JS transferred 1,129 KB 1,090 KB

Visual check

Both builds were driven through the same interactions, and the settled screenshots compared pixel by pixel. The states were: caps page, sidebar collapsed, spaces list expanded, org dropdown, user menu, notifications with the Comments tab, multi-select bar, Add Videos with a selection, the web recorder dialog, org settings, analytics, developers, Loom import, mobile nav, home (two scroll depths), student discount, Google Drive page, login and signup. All of them match, apart from a CSS animate-ping dot and a few antialiased pixels that also differ between two runs of main.

For the sidebar collapse, the spaces expansion, the notifications panel and the multi-select bar, frames were captured every 40 ms for 600 ms under Playwright's fake clock. Base against head stays within the frame-to-frame variance of base against base.

RetriggerView in GreptileConfidence Score: 5/5

The PR appears safe to merge; no blocking issues were found.

Summary

Updates apps/web to share framer-motion@12.42.2 with motion, removing the separate version 11 dependency tree.

  • Web pages use one shared version of the animation library.

Build and browser checks were not run; installed dependencies were unavailable.

Reviews (2) · Last reviewed commit: "perf(web): dedupe framer-motion onto the..." · Reviewed by Greptile

@vercel

vercel Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
cap-status Ready Ready Preview Oct 29, 2026 12:48am UTC

@richiemcilroy

Copy link
Copy Markdown
Member Author

hey @greptileai, please re-review the PR

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capy found no issues.

View 1 other finding in Capy.

Open in Capy

@richiemcilroy
richiemcilroy merged commit ac2843b into main Oct 29, 2026
53 checks passed

This branch was successfully deployed

2 active deployments
Preview – cap-web — 370d565e Deployed Oct 29, 2026 by vercel[bot]
Preview – cap-status — 370d565e Deployed Oct 29, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant