Performance Optimization: Making Sqrdo Fast and Responsive

Welcome to the fourth installment of our Sqrdo development journey! In this post, I'll be discussing one of the most critical aspects of any modern web application: performance optimization. As Sqrdo has evolved, I've continually refined its architecture and code to create a fast, responsive experience for users.

The Importance of Performance

When building a data-heavy application like Sqrdo, performance isn't just a nice-to-have—it's essential. Users need quick access to their commerce data to make informed business decisions. Slow loading times or laggy interfaces can lead to frustration and, ultimately, abandonment of the platform.

My performance optimization journey for Sqrdo has focused on several key areas:

1. Optimizing API Requests and Data Fetching

The Challenge

One of the earliest performance challenges was efficiently fetching data from the Squarespace API. Initial implementations had several issues:

  • Multiple redundant API calls
  • No caching strategy
  • Excessive re-renders when data changed
  • Poor handling of loading states

The Solution

I implemented several improvements to streamline the data fetching process:

State Management for API Calls

A key improvement was adding a dataFetched state in the Dashboard component to prevent multiple fetches and improve loading state management:

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

Simplified API Handler

I refactored the Squarespace API handler by removing unnecessary cookie store initialization and directly using the cookies function in createRouteHandlerClient:

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

2. Rendering Optimization

The Challenge

React's rendering behavior sometimes led to unnecessary re-renders, especially in data-heavy components like charts and tables. This was particularly noticeable when:

  • Filtering or sorting large datasets
  • Updating small pieces of UI state
  • Navigating between dashboard sections

The Solution

I implemented several techniques to optimize rendering:

Component Memoization

For expensive components, I used React.memo and careful dependency management:

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

Virtualized Lists

For long lists of customers or orders, I implemented virtualization to only render what's visible:

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

Suspense for Improved Loading

I implemented React Suspense throughout the application to improve the loading experience:

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

3. Build and Bundle Optimization

The Challenge

As the application grew, the bundle size increased, affecting initial load times. Additionally, ESLint and TypeScript checks during builds sometimes slowed down the development workflow.

The Solution

I made several configuration changes to optimize the build process:

Next.js Configuration Updates

Added ESLint and TypeScript build error handling in next.config.ts, allowing for skips based on environment variables:

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

Build Script Options

Introduced a new build script in package.json for building without linting:

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

Image Optimization

Added image optimization configurations to improve loading performance:

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

4. Progressive Web App (PWA) Enhancements

The Challenge

Users needed access to their dashboard from various devices, including mobile, and expected a native-like experience.

The Solution

I implemented PWA features to enhance the user experience across devices:

Web Manifest and Icons

Added app icons and a web manifest for improved PWA support:

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

Lessons Learned

Through this performance optimization journey, I've learned several valuable lessons:

1. Measure Before Optimizing

Always establish baseline metrics before making changes, then measure again after to confirm improvements.

2. Focus on User-Perceived Performance

Sometimes perceived performance is more important than actual performance metrics. Using loading skeletons and optimistic UI updates can make the app feel faster even when data is still loading.

3. Progressive Enhancement

Building features with progressive enhancement ensures that core functionality works for all users, with enhanced experiences for those with more capable devices and browsers.

4. Don't Optimize Prematurely

I found it's better to build features first, then optimize once real usage patterns emerge, rather than trying to optimize everything from the start.

Future Performance Enhancements

Looking ahead, I'm planning several additional performance improvements:

Incremental Static Regeneration: For frequently accessed but slowly changing data

Service Worker Caching: For offline access to key dashboard features

Preloading Critical Resources: Based on user navigation patterns

Code Splitting: Further refining the code splitting strategy for faster initial loads

Server Components: Leveraging React Server Components for data-heavy pages

Conclusion

Performance optimization has been an ongoing journey throughout Sqrdo's development. By focusing on API efficiency, rendering optimization, build improvements, and PWA features, I've created a fast, responsive application that helps Squarespace store owners access their commerce data quickly and efficiently.

In our next blog post, I'll explore how I approached the visual design and UI components to create a cohesive, accessible user experience.

Built by meireles at jnpr.dsgn