or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

asset-resolution.mdbuiltin-components.mdcomponents.mdcomposition-helpers.mddependency-injection.mderror-handling.mdhydration.mdindex.mdinternal-render-helpers.mdlifecycle.mdreactivity.mdscheduler-timing.mdssr-context.mdvdom-rendering.mdwatch-effects.md

hydration.mddocs/

0

# Hydration Strategies

1

2

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

3

4

## Capabilities

5

6

### Idle Hydration

7

8

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

9

10

```typescript { .api }

11

/**

12

* Hydrates component when browser is idle

13

* @param timeout - Maximum time to wait before forcing hydration (ms)

14

* @returns Hydration strategy function

15

*/

16

function hydrateOnIdle(timeout?: number): HydrationStrategy;

17

```

18

19

**Usage Examples:**

20

21

```typescript

22

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

23

24

// Hydrate when browser is idle

25

const IdleComponent = defineAsyncComponent({

26

loader: () => import('./HeavyComponent.vue'),

27

hydrate: hydrateOnIdle(1000) // Force hydration after 1 second if not idle

28

});

29

30

// Multiple components with idle hydration

31

const Dashboard = defineComponent({

32

components: {

33

Analytics: defineAsyncComponent({

34

loader: () => import('./Analytics.vue'),

35

hydrate: hydrateOnIdle()

36

}),

37

Charts: defineAsyncComponent({

38

loader: () => import('./Charts.vue'),

39

hydrate: hydrateOnIdle(2000)

40

})

41

}

42

});

43

```

44

45

### Visibility-based Hydration

46

47

Hydrate components when they become visible in the viewport.

48

49

```typescript { .api }

50

/**

51

* Hydrates component when it becomes visible

52

* @param options - Intersection observer options

53

* @returns Hydration strategy function

54

*/

55

function hydrateOnVisible(options?: IntersectionObserverInit): HydrationStrategy;

56

```

57

58

**Usage Examples:**

59

60

```typescript

61

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

62

63

// Hydrate when component becomes visible

64

const LazyImage = defineAsyncComponent({

65

loader: () => import('./LazyImage.vue'),

66

hydrate: hydrateOnVisible()

67

});

68

69

// Hydrate with custom intersection options

70

const BelowFoldContent = defineAsyncComponent({

71

loader: () => import('./BelowFoldContent.vue'),

72

hydrate: hydrateOnVisible({

73

rootMargin: '100px', // Hydrate 100px before entering viewport

74

threshold: 0.1 // Hydrate when 10% visible

75

})

76

});

77

78

// Multiple visibility thresholds

79

const ProgressiveImage = defineAsyncComponent({

80

loader: () => import('./ProgressiveImage.vue'),

81

hydrate: hydrateOnVisible({

82

threshold: [0, 0.25, 0.5, 0.75, 1] // Multiple visibility levels

83

})

84

});

85

```

86

87

### Media Query Hydration

88

89

Hydrate components based on CSS media query conditions.

90

91

```typescript { .api }

92

/**

93

* Hydrates component when media query matches

94

* @param query - CSS media query string

95

* @returns Hydration strategy function

96

*/

97

function hydrateOnMediaQuery(query: string): HydrationStrategy;

98

```

99

100

**Usage Examples:**

101

102

```typescript

103

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

104

105

// Hydrate only on desktop

106

const DesktopWidget = defineAsyncComponent({

107

loader: () => import('./DesktopWidget.vue'),

108

hydrate: hydrateOnMediaQuery('(min-width: 1024px)')

109

});

110

111

// Hydrate only on mobile

112

const MobileMenu = defineAsyncComponent({

113

loader: () => import('./MobileMenu.vue'),

114

hydrate: hydrateOnMediaQuery('(max-width: 768px)')

115

});

116

117

// Hydrate based on orientation

118

const LandscapeFeature = defineAsyncComponent({

119

loader: () => import('./LandscapeFeature.vue'),

120

hydrate: hydrateOnMediaQuery('(orientation: landscape)')

121

});

122

123

// Hydrate based on reduced motion preference

124

const AnimatedComponent = defineAsyncComponent({

125

loader: () => import('./AnimatedComponent.vue'),

126

hydrate: hydrateOnMediaQuery('(prefers-reduced-motion: no-preference)')

127

});

128

129

// Complex media queries

130

const HighResComponent = defineAsyncComponent({

131

loader: () => import('./HighResComponent.vue'),

132

hydrate: hydrateOnMediaQuery('(min-resolution: 192dpi) and (min-width: 1200px)')

133

});

134

```

135

136

### Interaction-based Hydration

137

138

Hydrate components when user interacts with them.

139

140

```typescript { .api }

141

/**

142

* Hydrates component on user interaction

143

* @param events - Event name or array of event names to listen for

144

* @returns Hydration strategy function

145

*/

146

function hydrateOnInteraction(events: string | string[]): HydrationStrategy;

147

```

148

149

**Usage Examples:**

150

151

```typescript

152

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

153

154

// Hydrate on click

155

const InteractiveWidget = defineAsyncComponent({

156

loader: () => import('./InteractiveWidget.vue'),

157

hydrate: hydrateOnInteraction('click')

158

});

159

160

// Hydrate on multiple events

161

const HoverCard = defineAsyncComponent({

162

loader: () => import('./HoverCard.vue'),

163

hydrate: hydrateOnInteraction(['mouseenter', 'focus'])

164

});

165

166

// Hydrate on touch or mouse events

167

const TouchComponent = defineAsyncComponent({

168

loader: () => import('./TouchComponent.vue'),

169

hydrate: hydrateOnInteraction(['touchstart', 'mousedown'])

170

});

171

172

// Form field hydration

173

const RichTextEditor = defineAsyncComponent({

174

loader: () => import('./RichTextEditor.vue'),

175

hydrate: hydrateOnInteraction(['focus', 'click', 'keydown'])

176

});

177

```

178

179

### Combined Hydration Strategies

180

181

Create complex hydration logic by combining multiple strategies.

182

183

```typescript

184

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

185

186

// Custom combined strategy

187

function createHybridStrategy(): HydrationStrategy {

188

return (hydrate, forEachElement) => {

189

let hydrated = false;

190

191

const doHydrate = () => {

192

if (!hydrated) {

193

hydrated = true;

194

hydrate();

195

}

196

};

197

198

// Hydrate on idle OR visibility OR interaction

199

const idleStrategy = hydrateOnIdle(2000);

200

const visibleStrategy = hydrateOnVisible({ threshold: 0.5 });

201

const interactionStrategy = hydrateOnInteraction(['click', 'focus']);

202

203

// Apply all strategies

204

idleStrategy(doHydrate, forEachElement);

205

visibleStrategy(doHydrate, forEachElement);

206

interactionStrategy(doHydrate, forEachElement);

207

};

208

}

209

210

// Usage

211

const HybridComponent = defineAsyncComponent({

212

loader: () => import('./HybridComponent.vue'),

213

hydrate: createHybridStrategy()

214

});

215

216

// Progressive hydration based on device capabilities

217

function createAdaptiveStrategy(): HydrationStrategy {

218

return (hydrate, forEachElement) => {

219

// Fast devices: hydrate immediately when visible

220

if (navigator.hardwareConcurrency > 4) {

221

hydrateOnVisible()(hydrate, forEachElement);

222

}

223

// Slow devices: hydrate only on interaction

224

else {

225

hydrateOnInteraction('click')(hydrate, forEachElement);

226

}

227

};

228

}

229

230

const AdaptiveComponent = defineAsyncComponent({

231

loader: () => import('./AdaptiveComponent.vue'),

232

hydrate: createAdaptiveStrategy()

233

});

234

```

235

236

### Advanced Usage Patterns

237

238

```typescript

239

// Conditional hydration based on feature detection

240

const AdvancedChart = defineAsyncComponent({

241

loader: () => import('./AdvancedChart.vue'),

242

hydrate: (() => {

243

// Only hydrate if Canvas is supported

244

if (typeof HTMLCanvasElement !== 'undefined') {

245

return hydrateOnVisible();

246

}

247

// Fallback: never hydrate (static content only)

248

return () => {};

249

})()

250

});

251

252

// Time-based hydration

253

function hydrateAfterDelay(delay: number): HydrationStrategy {

254

return (hydrate) => {

255

setTimeout(hydrate, delay);

256

};

257

}

258

259

const DelayedComponent = defineAsyncComponent({

260

loader: () => import('./DelayedComponent.vue'),

261

hydrate: hydrateAfterDelay(5000) // Hydrate after 5 seconds

262

});

263

264

// Hydrate based on network conditions

265

function hydrateOnGoodConnection(): HydrationStrategy {

266

return (hydrate) => {

267

const connection = (navigator as any).connection;

268

if (connection && connection.effectiveType === '4g') {

269

hydrateOnIdle()(hydrate, () => {});

270

} else {

271

hydrateOnInteraction('click')(hydrate, () => {});

272

}

273

};

274

}

275

276

const NetworkAwareComponent = defineAsyncComponent({

277

loader: () => import('./NetworkAwareComponent.vue'),

278

hydrate: hydrateOnGoodConnection()

279

});

280

```

281

282

## Types

283

284

```typescript { .api }

285

/**

286

* Hydration strategy function type

287

*/

288

interface HydrationStrategy {

289

(hydrate: () => void, forEachElement: (cb: (el: Element) => void) => void): void;

290

}

291

292

/**

293

* Factory function for creating hydration strategies

294

*/

295

interface HydrationStrategyFactory<T extends any[] = any[]> {

296

(...args: T): HydrationStrategy;

297

}

298

299

/**

300

* Intersection observer options for visibility-based hydration

301

*/

302

interface IntersectionObserverInit {

303

root?: Element | Document | null;

304

rootMargin?: string;

305

threshold?: number | number[];

306

}

307

```

308

309

## Performance Considerations

310

311

### Strategy Selection Guide

312

313

- **`hydrateOnIdle`**: Best for non-critical components that don't need immediate interactivity

314

- **`hydrateOnVisible`**: Ideal for below-the-fold content and images

315

- **`hydrateOnMediaQuery`**: Perfect for responsive components that only work on certain device types

316

- **`hydrateOnInteraction`**: Excellent for interactive widgets that users might not engage with

317

318

### Best Practices

319

320

1. **Prioritize Critical Path**: Always hydrate above-the-fold interactive content immediately

321

2. **Progressive Enhancement**: Design components to work without JavaScript first

322

3. **Fallback Strategies**: Provide timeout fallbacks to ensure eventual hydration

323

4. **Test Real Conditions**: Test hydration strategies on various devices and network conditions

324

5. **Monitor Performance**: Track metrics to ensure hydration strategies improve performance

325

326

### Example Application Structure

327

328

```typescript

329

const App = defineComponent({

330

components: {

331

// Critical: Hydrate immediately

332

Header: defineComponent(/* immediate hydration */),

333

Navigation: defineComponent(/* immediate hydration */),

334

335

// Important: Hydrate when visible

336

Hero: defineAsyncComponent({

337

loader: () => import('./Hero.vue'),

338

hydrate: hydrateOnVisible({ threshold: 0.1 })

339

}),

340

341

// Secondary: Hydrate when idle

342

Sidebar: defineAsyncComponent({

343

loader: () => import('./Sidebar.vue'),

344

hydrate: hydrateOnIdle(1000)

345

}),

346

347

// Interactive: Hydrate on interaction

348

ContactForm: defineAsyncComponent({

349

loader: () => import('./ContactForm.vue'),

350

hydrate: hydrateOnInteraction(['focus', 'click'])

351

}),

352

353

// Conditional: Hydrate based on device

354

MobileMenu: defineAsyncComponent({

355

loader: () => import('./MobileMenu.vue'),

356

hydrate: hydrateOnMediaQuery('(max-width: 768px)')

357

})

358

}

359

});

360

```