perf(VideoPlayer): lazy-load react-player to keep it out of the main bundle - #3204
Conversation
β¦bundle The default VideoPlayer statically imported react-player (~2 MB), pulling it into the SDK's eager import graph via index -> Attachment -> VideoAttachment. It is now code-split behind React.lazy: the react-player render moves to a default-exported ReactPlayerWrapper, dynamically imported so the consumer's bundler emits it as a separate chunk fetched only when a default video player renders. Consumers who override VideoPlayer via ComponentContext never load it. While the chunk loads, a Suspense fallback shows the overridable LoadingIndicator centered to fill the player box.
|
Size Change: +1.04 kB (+0.16%) Total Size: 653 kB π¦ View Changed
βΉοΈ View Unchanged
|
Codecov Reportβ
All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #3204 +/- ##
=======================================
Coverage 83.70% 83.70%
=======================================
Files 437 438 +1
Lines 13145 13148 +3
Branches 4255 4256 +1
=======================================
+ Hits 11003 11006 +3
Misses 2142 2142 β View full report in Codecov by Sentry. π New features to boost your workflow:
|
Adds the three vercel-labs/agent-skills used during the performance audit (vercel-composition-patterns, vercel-react-best-practices, web-design-guidelines) under .agents/skills, symlinked from .claude/skills and pinned via skills-lock.json. The content is third-party, so it is added to .prettierignore rather than reformatted to repo style.
|
Caution Review failedPull request was closed or merged during review π WalkthroughWalkthroughThis PR adds comprehensive React composition patterns and performance best practices documentation from Vercel Labs as vendored agent skills, plus refactors the VideoPlayer component for lazy loading with Suspense boundaries. ChangesAgent Skills Documentation
VideoPlayer Component Refactoring
Estimated code review effortπ― 3 (Moderate) | β±οΈ ~20 minutes
β¨ Finishing Touchesπ Generate docstrings
π§ͺ Generate unit tests (beta)
|
## [14.4.0](v14.3.0...v14.4.0) (2026-06-05) ### Bug Fixes * **compat:** restore React 17/18 compatibility in certain components ([#3197](#3197)) ([b513b69](b513b69)) * general performance and bug fixes ([#3201](#3201)) ([57c5795](57c5795)) * **interop:** unwrap CJS default exports (react-player, @emoji-mart/react) ([#3199](#3199)) ([4cddb02](4cddb02)) * maintain topmost modal non-inert ([#3206](#3206)) ([7ad98fa](7ad98fa)) ### Features * allow to stack modals on top of each other ([#3203](#3203)) ([4c934ae](4c934ae)) * display notifications above modals ([#3200](#3200)) ([0433090](0433090)) * **Reactions:** send emoji_code with reactions for push notification rendering ([#3209](#3209)) ([2faa620](2faa620)) ### Performance Improvements * **Message:** hoist regex compilation in message text rendering ([#3202](#3202)) ([8c018a4](8c018a4)) * **VideoPlayer:** lazy-load react-player to keep it out of the main bundle ([#3204](#3204)) ([18dc966](18dc966))
|
π This PR is included in version 14.4.0 π The release is available on: Your semantic-release bot π¦π |
π― Goal
Stop pulling
react-player(~2 MB) into the SDK's eager import graph β finding #4 from the Vercel React best-practices audit (PERFORMANCE_AUDIT.md,bundle-dynamic-imports).react-playeris only needed when a default video attachment renders, yet the static import chain (indexβAttachmentβVideoAttachmentβVideoPlayer) forced it into every consumer's main chunk β including for consumers who never show video or who override the player.π Implementation details
react-playerrender (plus the existing.defaultCJS-interop unwrap) into a new default-exported internal moduleVideoPlayer/ReactPlayerWrapper.tsx.VideoPlayer.tsxnow loads it viaReact.lazy(() => import('./ReactPlayerWrapper'))inside<React.Suspense>. TheComponentContext.VideoPlayeroverride branch and the publicVideoPlayerexport /VideoPlayerPropsare unchanged.LoadingIndicator(read fromComponentContext), wrapped in.str-chat__video-player-loadingto fill + center within the player box so it doesn't flash as a stray top-left icon or shift layout when the player mounts. New SCSSVideoPlayer/styling/VideoPlayer.scss,@used from the VideoPlayer styling entry.dist/es/index.mjsthere is no staticfrom "react-player"β insteadimport("./ReactPlayerWrapper.<hash>.mjs"), andreact-playeris imported only inside that wrapper chunk. The consumer's bundler thus emits it as a separate, on-demand chunk; consumers overridingVideoPlayer/Medianever load it.React.lazyisn't server-renderable on React 17; default video rendering is client-only. SSR consumers can supply a synchronousVideoPlayerviaComponentContext(unchanged path).VideoAttachment/Attachment/Gallerysuites render via overrides and are unaffected. AddedVideoPlayer/__tests__/VideoPlayer.test.tsxcovering the lazy default render (async) and the override path (noreact-playerload).Verification:
yarn types, ESLint (--max-warnings 0), Prettier (TS + SCSS),yarn build-styling(rule present indist/css/index.css),vite buildchunk-split confirmed, and the video/attachment/gallery Vitest suites all pass.π¨ UI Changes
No change to the rendered player. One new transient state: a centered loading spinner shown for the brief moment the
react-playerchunk is fetched (previously the player simply appeared once its eagerly-bundled code ran). No screenshots needed.π¦ Note β second commit vendors agent skills (separate concern)
This PR also contains a separate
chore:commit,chore: vendor Vercel agent skills used for the performance audit, unrelated to the VideoPlayer change. It vendors the threevercel-labs/agent-skillsused to produce the audit (vercel-composition-patterns,vercel-react-best-practices,web-design-guidelines) under.agents/skills, symlinked from.claude/skills(relative, in-repo symlinks) and pinned viaskills-lock.json. The third-party content is added to.prettierignorerather than reformatted to repo style.It's isolated in its own commit, so it can be split into a dedicated PR or dropped if reviewers would prefer to keep this PR perf-only.
Summary by CodeRabbit
New Features
Improvements