Client-Side Hydration
NEW IN v1.0.0
🎉 Client-side hydration is a major new feature in v1.0.0! This makes WP Block to HTML the first WordPress block converter with production-ready hydration capabilities for SSR scenarios.
Client-side hydration allows you to progressively add interactivity to server-rendered content, providing optimal performance by loading interactive components only when needed.
Overview
The hydration system in WP Block to HTML v1.0.0 provides four distinct strategies to optimize when and how interactive components are loaded:
- Immediate: Hydrate components immediately on page load
- Viewport: Hydrate when components enter the viewport
- Interaction: Hydrate on user interaction (hover, click, focus)
- Idle: Hydrate during browser idle time
Quick Start
import { convertBlocks } from 'wp-block-to-html';
import { HydrationManager } from 'wp-block-to-html/hydration';
// Convert blocks with hydration configuration
const html = convertBlocks(blocks, {
hydration: {
strategy: 'viewport',
priorityBlocks: ['core/button', 'core/gallery']
}
});
// Initialize hydration manager
const hydrationManager = new HydrationManager({
strategy: 'viewport',
rootSelector: '#app',
throttle: 100
});
// Start hydration
await hydrationManager.hydrateAll();
Hydration Strategies
Immediate Hydration
Hydrates components immediately on page load. Best for critical interactive components that users expect to work immediately.
const hydrationManager = new HydrationManager({
strategy: 'immediate',
rootSelector: '#app'
});
await hydrationManager.hydrateAll();
Viewport-Based Hydration
Hydrates components when they enter the viewport using IntersectionObserver. Ideal for performance optimization with long-form content.
const hydrationManager = new HydrationManager({
strategy: 'viewport',
rootSelector: '#app',
viewportOptions: {
threshold: 0.1,
rootMargin: '50px'
}
});
await hydrationManager.hydrateAll();
Interaction-Based Hydration
Hydrates components on user interaction events (hover, click, focus). Perfect for components that are only interactive on demand.
const hydrationManager = new HydrationManager({
strategy: 'interaction',
rootSelector: '#app',
interactionEvents: ['mouseenter', 'click', 'focusin']
});
await hydrationManager.hydrateAll();
Idle Hydration
Hydrates components during browser idle time using requestIdleCallback. Best for non-critical interactive components.
const hydrationManager = new HydrationManager({
strategy: 'idle',
rootSelector: '#app',
idleTimeout: 5000 // Fallback timeout
});
await hydrationManager.hydrateAll();
Advanced Configuration
Priority Blocks
Specify which block types should be hydrated first for optimal user experience:
const html = convertBlocks(blocks, {
hydration: {
strategy: 'progressive',
priorityBlocks: [
'core/button',
'core/gallery',
'core/video',
'core/audio'
],
fallbackStrategy: 'idle'
}
});
Mixed Strategies
Use different strategies for different types of blocks:
const hydrationManager = new HydrationManager({
strategy: 'mixed',
strategyMap: {
'core/button': 'immediate',
'core/gallery': 'viewport',
'core/video': 'interaction',
'core/embed': 'idle'
},
defaultStrategy: 'viewport'
});
Custom Hydration Logic
Implement custom hydration logic for specific use cases:
const hydrationManager = new HydrationManager({
strategy: 'custom',
customHydrator: async (blockElement, blockType) => {
// Custom logic based on block type, user preferences, etc.
if (blockType === 'core/gallery' && window.innerWidth < 768) {
// Mobile-specific hydration
await hydrateForMobile(blockElement);
} else {
// Default hydration
await hydrateBlock(blockElement, blockType);
}
}
});
Framework Integration
React Components
import { createReactComponent } from 'wp-block-to-html/react';
import { HydrationManager } from 'wp-block-to-html/hydration';
const BlockComponent = createReactComponent(blocks, {
cssFramework: 'tailwind',
hydration: {
strategy: 'viewport',
reactOptions: {
suspense: true,
errorBoundary: true
}
}
});
// Hydrate React components
const hydrationManager = new HydrationManager({
strategy: 'viewport',
framework: 'react',
rootSelector: '#react-app'
});
Vue Components
import { createVueComponent } from 'wp-block-to-html/vue';
import { HydrationManager } from 'wp-block-to-html/hydration';
const BlockComponent = createVueComponent(blocks, {
cssFramework: 'tailwind',
hydration: {
strategy: 'interaction',
vueOptions: {
async: true,
teleport: true
}
}
});
// Hydrate Vue components
const hydrationManager = new HydrationManager({
strategy: 'interaction',
framework: 'vue',
rootSelector: '#vue-app'
});
Performance Optimization
Throttling and Debouncing
const hydrationManager = new HydrationManager({
strategy: 'viewport',
throttle: 100, // Throttle viewport checks
debounce: 250 // Debounce hydration calls
});
Batch Hydration
// Hydrate multiple blocks in batches for better performance
const hydrationManager = new HydrationManager({
strategy: 'viewport',
batchSize: 5,
batchDelay: 16 // ~60fps
});
await hydrationManager.hydrateBatch(['block-1', 'block-2', 'block-3']);
Memory Management
// Automatic cleanup of hydrated components
const hydrationManager = new HydrationManager({
strategy: 'viewport',
autoCleanup: true,
cleanupDelay: 30000 // Clean up after 30s outside viewport
});
// Manual cleanup
hydrationManager.cleanup('block-id');
hydrationManager.cleanupAll();
Error Handling
const hydrationManager = new HydrationManager({
strategy: 'viewport',
onError: (error, blockId, blockType) => {
console.error(`Hydration failed for ${blockType} (${blockId}):`, error);
// Report to error tracking service
errorTracker.report(error, { blockId, blockType });
// Fallback to static rendering
return false; // Don't retry
},
retryAttempts: 3,
retryDelay: 1000
});
Monitoring and Analytics
const hydrationManager = new HydrationManager({
strategy: 'viewport',
onHydrationStart: (blockId, blockType) => {
performance.mark(`hydration-start-${blockId}`);
},
onHydrationComplete: (blockId, blockType, duration) => {
performance.mark(`hydration-end-${blockId}`);
performance.measure(`hydration-${blockId}`,
`hydration-start-${blockId}`,
`hydration-end-${blockId}`
);
// Send analytics
analytics.track('block_hydrated', {
blockType,
duration,
strategy: 'viewport'
});
}
});
Best Practices
1. Choose the Right Strategy
- Immediate: Critical navigation, forms, buttons above the fold
- Viewport: Galleries, videos, maps, interactive content below fold
- Interaction: Tooltips, modals, expandable content
- Idle: Analytics, tracking, non-critical widgets
2. Optimize Bundle Size
// Import only the hydration features you need
import { HydrationManager } from 'wp-block-to-html/hydration/core';
import { ViewportStrategy } from 'wp-block-to-html/hydration/strategies/viewport';
const hydrationManager = new HydrationManager({
strategy: new ViewportStrategy({
threshold: 0.1,
rootMargin: '50px'
})
});
3. Progressive Enhancement
// Ensure graceful degradation
const html = convertBlocks(blocks, {
hydration: {
strategy: 'progressive',
fallbackToStatic: true, // Render static version if hydration fails
enableNoScript: true // Include noscript fallbacks
}
});
4. Test Performance
// Measure hydration impact
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.name.includes('hydration')) {
console.log(`${entry.name}: ${entry.duration}ms`);
}
}
});
observer.observe({ entryTypes: ['measure'] });
API Reference
HydrationManager
interface HydrationManagerOptions {
strategy: 'immediate' | 'viewport' | 'interaction' | 'idle' | 'mixed' | 'custom';
rootSelector: string;
framework?: 'react' | 'vue' | 'angular' | 'svelte';
throttle?: number;
debounce?: number;
batchSize?: number;
batchDelay?: number;
autoCleanup?: boolean;
cleanupDelay?: number;
retryAttempts?: number;
retryDelay?: number;
onHydrationStart?: (blockId: string, blockType: string) => void;
onHydrationComplete?: (blockId: string, blockType: string, duration: number) => void;
onError?: (error: Error, blockId: string, blockType: string) => boolean;
}
Methods
class HydrationManager {
// Hydrate all blocks
async hydrateAll(): Promise<void>;
// Hydrate specific block
async hydrateBlock(blockId: string): Promise<void>;
// Hydrate batch of blocks
async hydrateBatch(blockIds: string[]): Promise<void>;
// Cleanup hydrated blocks
cleanup(blockId: string): void;
cleanupAll(): void;
// Check if block is hydrated
isHydrated(blockId: string): boolean;
// Get hydration stats
getStats(): HydrationStats;
}
Migration from Server-Only Rendering
If you're migrating from server-only rendering to hydration:
- Start with Idle Strategy: Begin with
idle
hydration to ensure no performance regression - Identify Critical Components: Move important interactive elements to
immediate
- Optimize Progressively: Use
viewport
for below-fold content - Add Interaction Loading: Use
interaction
for secondary features - Monitor Performance: Track Core Web Vitals and hydration timing
// Migration-friendly configuration
const html = convertBlocks(blocks, {
hydration: {
strategy: 'progressive',
migrationMode: true, // Enables additional safety checks
fallbackToStatic: true,
performanceMonitoring: true
}
});
Troubleshooting
Common Issues
- Hydration Mismatch: Server and client HTML don't match
- Double Hydration: Components hydrated multiple times
- Memory Leaks: Hydrated components not cleaned up
- Performance Regression: Hydration blocking main thread
Debug Mode
const hydrationManager = new HydrationManager({
strategy: 'viewport',
debug: true, // Enables console logging
debugLevel: 'verbose' // 'minimal' | 'normal' | 'verbose'
});
The hydration system in WP Block to HTML v1.0.0 provides powerful tools for optimizing interactive content loading while maintaining excellent performance and user experience.