Case Study
Dashboard Performance Optimization
Eliminated main-thread blocking in a data-heavy analytics dashboard rendering thousands of rows and real-time updates.
Problem
The dashboard rendered 5,000+ rows in a single unvirtualised component tree. Initial load blocked the main thread for over 3 seconds. Sorting or filtering triggered full re-renders, making the interface feel broken. Users had started reporting the dashboard as unusable on lower-end hardware.
Approach
Profiled the component tree with Vue DevTools and Chrome Performance panel before touching any code. Identified three root causes: unvirtualised list rendering, unnecessary computed re-evaluations on unrelated state changes, and synchronous data transforms running on the main thread. Fixed in order of impact.
Architecture
- Frontend: Vue 3 with targeted, measured performance changes
- List rendering: Virtual scrolling via vue-virtual-scroller
- Data processing: Web Worker handling sort and filter transforms
- State: Computed properties with explicit, narrow dependency tracking
- Code splitting: Chart components loaded with defineAsyncComponent
Key Decisions
Virtual scrolling only where it measured
Not every list needed virtualisation. Applied it only to tables exceeding 500 rows after profiling. Avoided adding abstraction complexity where the performance gain was negligible.
Web Worker for data transforms
Moving filter and sort logic off the main thread eliminated UI jank during heavy operations. Workers communicated via structured clone — no shared-state race conditions.
Code-split chart components
Chart libraries accounted for a large share of the initial bundle. Lazy loading them reduced bundle size by 34% and directly improved TTI.
Profile first, optimise second
Every change was preceded by a measurement. This prevented wasted effort on already-fast components and kept the diff small, reviewable, and easy to revert.
Result
Time to Interactive dropped 41%. Main thread blocking during interactions went from 3s+ to under 200ms. User-reported freezing complaints stopped after the first deployment. Dashboard now handles 10,000+ rows without degradation.
Tech Stack
What I'd Improve
- Move real-time data to a WebSocket connection for lower latency updates
- Add server-side pagination to reduce initial data payload on slow connections