Skip to main content

Performance Optimization

Advanced techniques for optimizing O2VEND theme and app performance.

Overview

Performance optimization is crucial for providing a fast, responsive user experience. This guide covers advanced techniques for optimizing themes and apps.

Performance Metrics

Key Metrics to Monitor

  • First Contentful Paint (FCP): < 1.8s
  • Largest Contentful Paint (LCP): < 2.5s
  • Time to Interactive (TTI): < 3.8s
  • Total Blocking Time (TBT): < 200ms
  • Cumulative Layout Shift (CLS): < 0.1

Theme Performance Optimization

1. Template Optimization

Minimize Liquid Logic

Avoid complex logic in templates:

{% for collection in collections %}
{% for product in collection.products %}
{% for variant in product.variants %}
{% for option in variant.options %}
{{ option.name }}
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}

Use snippets to break down complexity:

{% for collection in collections %}
{% render 'collection-grid', collection: collection %}
{% endfor %}

Cache Expensive Operations

{% assign product_count = collection.products.size %}
{% assign has_discount = product.compare_at_price > product.price %}
{% assign formatted_price = product.price | money %}

2. Asset Optimization

Minify CSS and JavaScript

# Minify CSS
cssnano theme.css > theme.min.css

# Minify JavaScript
terser theme.js > theme.min.js

Combine Files

<!-- Instead of multiple files -->
{{ 'theme.css' | asset_url | stylesheet_tag }}
{{ 'components.css' | asset_url | stylesheet_tag }}

<!-- Combine into one -->
{{ 'theme.min.css' | asset_url | stylesheet_tag }}

Optimize Images

  • Use WebP format when possible
  • Implement responsive images
  • Lazy load images below the fold
  • Compress images (target 70-80% quality)

3. Widget Performance

Limit Widget Count

{% assign limited_widgets = widgets.content | limit: 10 %}
{% for widget in limited_widgets %}
{{ widget | render_widget }}
{% endfor %}

Lazy Load Widgets

<div class="lazy-widget" data-widget-id="{{ widget.id }}">
<!-- Widget placeholder -->
</div>

<script>
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
loadWidget(entry.target);
observer.unobserve(entry.target);
}
});
});
</script>

App Performance Optimization

1. Efficient Hook Implementation

Minimize Hook Processing Time

// ❌ Slow: Processing in hook
liquid.registerHook('theme_head', (context) => {
// Heavy processing
const data = processLargeDataset();
return data;
});

// ✅ Fast: Cache results
const cachedData = processLargeDataset();
liquid.registerHook('theme_head', (context) => {
return cachedData;
});

2. Asset Loading

Defer Non-Critical Assets

<!-- Critical CSS inline -->
<style>
/* Critical styles */
</style>

<!-- Non-critical CSS deferred -->
<link rel="preload" href="{{ 'theme.css' | asset_url }}" as="style" onload="this.onload=null;this.rel='stylesheet'">

API Performance

1. Request Optimization

Batch Requests

// ❌ Multiple requests
const products = await api.getProducts();
const categories = await api.getCategories();
const brands = await api.getBrands();

// ✅ Single batch request
const data = await api.batch({
products: '/products',
categories: '/categories',
brands: '/brands'
});

Implement Caching

const cache = new Map();

async function getCachedData(key, fetcher) {
if (cache.has(key)) {
return cache.get(key);
}
const data = await fetcher();
cache.set(key, data);
return data;
}

2. Pagination

Use Efficient Pagination

// Use cursor-based pagination when available
const products = await api.getProducts({
page: 1,
pageSize: 20,
cursor: lastCursor
});

Database Optimization

1. Query Optimization

  • Use indexes on frequently queried fields
  • Limit result sets
  • Use projections to fetch only needed fields
  • Implement connection pooling

2. Caching Strategy

// Multi-level caching
const cache = {
memory: new Map(),
redis: redisClient,

async get(key) {
// Check memory cache
if (this.memory.has(key)) {
return this.memory.get(key);
}

// Check Redis cache
const redisValue = await this.redis.get(key);
if (redisValue) {
this.memory.set(key, redisValue);
return redisValue;
}

return null;
}
};

Monitoring and Profiling

1. Performance Monitoring

// Measure performance
performance.mark('start');
// ... code ...
performance.mark('end');
performance.measure('operation', 'start', 'end');
console.log(performance.getEntriesByName('operation'));

2. Error Tracking

// Track performance errors
window.addEventListener('error', (event) => {
// Send to monitoring service
trackError({
message: event.message,
filename: event.filename,
lineno: event.lineno
});
});

Best Practices

  1. Measure First: Always measure before optimizing
  2. Optimize Critical Path: Focus on above-the-fold content
  3. Lazy Load: Defer non-critical resources
  4. Cache Aggressively: Cache API responses and computed values
  5. Minify Assets: Always minify production assets
  6. Monitor Performance: Continuously monitor performance metrics
  7. Test Regularly: Performance test after each change

Tools

  • Lighthouse: Performance auditing
  • WebPageTest: Detailed performance analysis
  • Chrome DevTools: Performance profiling
  • Bundle Analyzer: Analyze JavaScript bundles