CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-vue--runtime-core

Vue.js 3 runtime core library providing foundational APIs for building custom renderers and managing reactive component systems

Pending
Overview
Eval results
Files

hydration.mddocs/

Hydration Strategies

Vue provides advanced hydration strategies for selective server-side rendering and client-side hydration, enabling performance optimizations for different content types.

Capabilities

Idle Hydration

Hydrate components when the browser is idle, reducing impact on initial page load.

/**
 * Hydrates component when browser is idle
 * @param timeout - Maximum time to wait before forcing hydration (ms)
 * @returns Hydration strategy function
 */
function hydrateOnIdle(timeout?: number): HydrationStrategy;

Usage Examples:

import { defineAsyncComponent, hydrateOnIdle } from "@vue/runtime-core";

// Hydrate when browser is idle
const IdleComponent = defineAsyncComponent({
  loader: () => import('./HeavyComponent.vue'),
  hydrate: hydrateOnIdle(1000) // Force hydration after 1 second if not idle
});

// Multiple components with idle hydration
const Dashboard = defineComponent({
  components: {
    Analytics: defineAsyncComponent({
      loader: () => import('./Analytics.vue'),
      hydrate: hydrateOnIdle()
    }),
    Charts: defineAsyncComponent({
      loader: () => import('./Charts.vue'), 
      hydrate: hydrateOnIdle(2000)
    })
  }
});

Visibility-based Hydration

Hydrate components when they become visible in the viewport.

/**
 * Hydrates component when it becomes visible
 * @param options - Intersection observer options
 * @returns Hydration strategy function
 */
function hydrateOnVisible(options?: IntersectionObserverInit): HydrationStrategy;

Usage Examples:

import { defineAsyncComponent, hydrateOnVisible } from "@vue/runtime-core";

// Hydrate when component becomes visible
const LazyImage = defineAsyncComponent({
  loader: () => import('./LazyImage.vue'),
  hydrate: hydrateOnVisible()
});

// Hydrate with custom intersection options
const BelowFoldContent = defineAsyncComponent({
  loader: () => import('./BelowFoldContent.vue'),
  hydrate: hydrateOnVisible({
    rootMargin: '100px', // Hydrate 100px before entering viewport
    threshold: 0.1 // Hydrate when 10% visible
  })
});

// Multiple visibility thresholds
const ProgressiveImage = defineAsyncComponent({
  loader: () => import('./ProgressiveImage.vue'),
  hydrate: hydrateOnVisible({
    threshold: [0, 0.25, 0.5, 0.75, 1] // Multiple visibility levels
  })
});

Media Query Hydration

Hydrate components based on CSS media query conditions.

/**
 * Hydrates component when media query matches
 * @param query - CSS media query string
 * @returns Hydration strategy function
 */
function hydrateOnMediaQuery(query: string): HydrationStrategy;

Usage Examples:

import { defineAsyncComponent, hydrateOnMediaQuery } from "@vue/runtime-core";

// Hydrate only on desktop
const DesktopWidget = defineAsyncComponent({
  loader: () => import('./DesktopWidget.vue'),
  hydrate: hydrateOnMediaQuery('(min-width: 1024px)')
});

// Hydrate only on mobile
const MobileMenu = defineAsyncComponent({
  loader: () => import('./MobileMenu.vue'),
  hydrate: hydrateOnMediaQuery('(max-width: 768px)')
});

// Hydrate based on orientation
const LandscapeFeature = defineAsyncComponent({
  loader: () => import('./LandscapeFeature.vue'),
  hydrate: hydrateOnMediaQuery('(orientation: landscape)')
});

// Hydrate based on reduced motion preference
const AnimatedComponent = defineAsyncComponent({
  loader: () => import('./AnimatedComponent.vue'),
  hydrate: hydrateOnMediaQuery('(prefers-reduced-motion: no-preference)')
});

// Complex media queries
const HighResComponent = defineAsyncComponent({
  loader: () => import('./HighResComponent.vue'),
  hydrate: hydrateOnMediaQuery('(min-resolution: 192dpi) and (min-width: 1200px)')
});

Interaction-based Hydration

Hydrate components when user interacts with them.

/**
 * Hydrates component on user interaction
 * @param events - Event name or array of event names to listen for
 * @returns Hydration strategy function
 */
function hydrateOnInteraction(events: string | string[]): HydrationStrategy;

Usage Examples:

import { defineAsyncComponent, hydrateOnInteraction } from "@vue/runtime-core";

// Hydrate on click
const InteractiveWidget = defineAsyncComponent({
  loader: () => import('./InteractiveWidget.vue'),
  hydrate: hydrateOnInteraction('click')
});

// Hydrate on multiple events
const HoverCard = defineAsyncComponent({
  loader: () => import('./HoverCard.vue'),
  hydrate: hydrateOnInteraction(['mouseenter', 'focus'])
});

// Hydrate on touch or mouse events
const TouchComponent = defineAsyncComponent({
  loader: () => import('./TouchComponent.vue'),
  hydrate: hydrateOnInteraction(['touchstart', 'mousedown'])
});

// Form field hydration
const RichTextEditor = defineAsyncComponent({
  loader: () => import('./RichTextEditor.vue'),
  hydrate: hydrateOnInteraction(['focus', 'click', 'keydown'])
});

Combined Hydration Strategies

Create complex hydration logic by combining multiple strategies.

import { defineAsyncComponent, hydrateOnIdle, hydrateOnVisible, hydrateOnMediaQuery, hydrateOnInteraction } from "@vue/runtime-core";

// Custom combined strategy
function createHybridStrategy(): HydrationStrategy {
  return (hydrate, forEachElement) => {
    let hydrated = false;
    
    const doHydrate = () => {
      if (!hydrated) {
        hydrated = true;
        hydrate();
      }
    };
    
    // Hydrate on idle OR visibility OR interaction
    const idleStrategy = hydrateOnIdle(2000);
    const visibleStrategy = hydrateOnVisible({ threshold: 0.5 });
    const interactionStrategy = hydrateOnInteraction(['click', 'focus']);
    
    // Apply all strategies
    idleStrategy(doHydrate, forEachElement);
    visibleStrategy(doHydrate, forEachElement);
    interactionStrategy(doHydrate, forEachElement);
  };
}

// Usage
const HybridComponent = defineAsyncComponent({
  loader: () => import('./HybridComponent.vue'),
  hydrate: createHybridStrategy()
});

// Progressive hydration based on device capabilities
function createAdaptiveStrategy(): HydrationStrategy {
  return (hydrate, forEachElement) => {
    // Fast devices: hydrate immediately when visible
    if (navigator.hardwareConcurrency > 4) {
      hydrateOnVisible()(hydrate, forEachElement);
    }
    // Slow devices: hydrate only on interaction
    else {
      hydrateOnInteraction('click')(hydrate, forEachElement);
    }
  };
}

const AdaptiveComponent = defineAsyncComponent({
  loader: () => import('./AdaptiveComponent.vue'),
  hydrate: createAdaptiveStrategy()
});

Advanced Usage Patterns

// Conditional hydration based on feature detection
const AdvancedChart = defineAsyncComponent({
  loader: () => import('./AdvancedChart.vue'),
  hydrate: (() => {
    // Only hydrate if Canvas is supported
    if (typeof HTMLCanvasElement !== 'undefined') {
      return hydrateOnVisible();
    }
    // Fallback: never hydrate (static content only)
    return () => {};
  })()
});

// Time-based hydration
function hydrateAfterDelay(delay: number): HydrationStrategy {
  return (hydrate) => {
    setTimeout(hydrate, delay);
  };
}

const DelayedComponent = defineAsyncComponent({
  loader: () => import('./DelayedComponent.vue'),
  hydrate: hydrateAfterDelay(5000) // Hydrate after 5 seconds
});

// Hydrate based on network conditions
function hydrateOnGoodConnection(): HydrationStrategy {
  return (hydrate) => {
    const connection = (navigator as any).connection;
    if (connection && connection.effectiveType === '4g') {
      hydrateOnIdle()(hydrate, () => {});
    } else {
      hydrateOnInteraction('click')(hydrate, () => {});
    }
  };
}

const NetworkAwareComponent = defineAsyncComponent({
  loader: () => import('./NetworkAwareComponent.vue'),
  hydrate: hydrateOnGoodConnection()
});

Types

/**
 * Hydration strategy function type
 */
interface HydrationStrategy {
  (hydrate: () => void, forEachElement: (cb: (el: Element) => void) => void): void;
}

/**
 * Factory function for creating hydration strategies
 */
interface HydrationStrategyFactory<T extends any[] = any[]> {
  (...args: T): HydrationStrategy;
}

/**
 * Intersection observer options for visibility-based hydration
 */
interface IntersectionObserverInit {
  root?: Element | Document | null;
  rootMargin?: string;
  threshold?: number | number[];
}

Performance Considerations

Strategy Selection Guide

  • hydrateOnIdle: Best for non-critical components that don't need immediate interactivity
  • hydrateOnVisible: Ideal for below-the-fold content and images
  • hydrateOnMediaQuery: Perfect for responsive components that only work on certain device types
  • hydrateOnInteraction: Excellent for interactive widgets that users might not engage with

Best Practices

  1. Prioritize Critical Path: Always hydrate above-the-fold interactive content immediately
  2. Progressive Enhancement: Design components to work without JavaScript first
  3. Fallback Strategies: Provide timeout fallbacks to ensure eventual hydration
  4. Test Real Conditions: Test hydration strategies on various devices and network conditions
  5. Monitor Performance: Track metrics to ensure hydration strategies improve performance

Example Application Structure

const App = defineComponent({
  components: {
    // Critical: Hydrate immediately
    Header: defineComponent(/* immediate hydration */),
    Navigation: defineComponent(/* immediate hydration */),
    
    // Important: Hydrate when visible
    Hero: defineAsyncComponent({
      loader: () => import('./Hero.vue'),
      hydrate: hydrateOnVisible({ threshold: 0.1 })
    }),
    
    // Secondary: Hydrate when idle
    Sidebar: defineAsyncComponent({
      loader: () => import('./Sidebar.vue'),
      hydrate: hydrateOnIdle(1000)
    }),
    
    // Interactive: Hydrate on interaction
    ContactForm: defineAsyncComponent({
      loader: () => import('./ContactForm.vue'),
      hydrate: hydrateOnInteraction(['focus', 'click'])
    }),
    
    // Conditional: Hydrate based on device
    MobileMenu: defineAsyncComponent({
      loader: () => import('./MobileMenu.vue'),
      hydrate: hydrateOnMediaQuery('(max-width: 768px)')
    })
  }
});

Install with Tessl CLI

npx tessl i tessl/npm-vue--runtime-core

docs

asset-resolution.md

builtin-components.md

components.md

composition-helpers.md

dependency-injection.md

error-handling.md

hydration.md

index.md

internal-render-helpers.md

lifecycle.md

reactivity.md

scheduler-timing.md

ssr-context.md

vdom-rendering.md

watch-effects.md

tile.json