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

internal-render-helpers.mddocs/

0

# Internal Render Helpers

1

2

Vue's internal render helpers provide low-level utilities for advanced rendering scenarios, custom renderers, and compiler-generated code. These APIs are primarily used by Vue's template compiler and custom renderer implementations.

3

4

## Capabilities

5

6

### Block Tracking

7

8

Control Vue's block tracking system for optimized re-rendering.

9

10

```typescript { .api }

11

/**

12

* Opens a new block for tracking dynamic children

13

* @param disableTracking - Whether to disable tracking for this block

14

*/

15

function openBlock(disableTracking?: boolean): void;

16

17

/**

18

* Creates a block VNode with tracked dynamic children

19

* @param type - Element type or component

20

* @param props - Element/component props

21

* @param children - Child nodes

22

* @param patchFlag - Optimization hints

23

* @param dynamicProps - Names of dynamic props

24

* @returns Block VNode

25

*/

26

function createBlock(

27

type: VNodeTypes,

28

props?: VNodeProps | null,

29

children?: VNodeArrayChildren,

30

patchFlag?: number,

31

dynamicProps?: string[]

32

): VNode;

33

34

/**

35

* Sets the block tracking value

36

* @param value - Positive number enables tracking, 0 or negative disables

37

*/

38

function setBlockTracking(value: number): void;

39

```

40

41

**Usage Examples:**

42

43

```typescript

44

import { openBlock, createBlock, setBlockTracking, h } from "@vue/runtime-core";

45

46

// Manual block creation (typically done by compiler)

47

const createOptimizedElement = () => {

48

openBlock();

49

50

return createBlock('div', { class: 'container' }, [

51

h('span', 'Static content'),

52

// Dynamic content will be tracked

53

h('span', { key: Math.random() }, 'Dynamic content')

54

]);

55

};

56

57

// Disable tracking for certain scenarios

58

const createUnoptimizedElement = () => {

59

setBlockTracking(-1); // Disable tracking

60

61

const element = h('div', [

62

h('span', 'This won\'t be optimized')

63

]);

64

65

setBlockTracking(1); // Re-enable tracking

66

67

return element;

68

};

69

70

// Conditional block tracking

71

const createConditionalBlock = (optimize: boolean) => {

72

if (optimize) {

73

openBlock();

74

return createBlock('div', null, [

75

// Children will be tracked for optimization

76

]);

77

} else {

78

return h('div', [

79

// Children won't be tracked

80

]);

81

}

82

};

83

```

84

85

### VNode Creation Helpers

86

87

Low-level VNode creation functions for specific node types.

88

89

```typescript { .api }

90

/**

91

* Creates a text VNode

92

* @param text - Text content

93

* @param flag - Patch flag for optimization

94

* @returns Text VNode

95

*/

96

function createTextVNode(text?: string, flag?: number): VNode;

97

98

/**

99

* Creates a comment VNode

100

* @param text - Comment content

101

* @param asBlock - Whether to create as block

102

* @returns Comment VNode

103

*/

104

function createCommentVNode(text?: string, asBlock?: boolean): VNode;

105

106

/**

107

* Creates a static VNode for hoisted content

108

* @param content - Static HTML content

109

* @param numberOfNodes - Number of nodes in the content

110

* @returns Static VNode

111

*/

112

function createStaticVNode(content: string, numberOfNodes: number): VNode;

113

114

/**

115

* Creates an element VNode

116

* @param type - Element tag name

117

* @param props - Element properties

118

* @param children - Child nodes

119

* @param patchFlag - Optimization flag

120

* @param dynamicProps - Dynamic property names

121

* @returns Element VNode

122

*/

123

function createElementVNode(

124

type: string,

125

props?: VNodeProps | null,

126

children?: VNodeArrayChildren,

127

patchFlag?: number,

128

dynamicProps?: string[]

129

): VNode;

130

131

/**

132

* Creates an element block VNode (with tracking)

133

* @param type - Element tag name

134

* @param props - Element properties

135

* @param children - Child nodes

136

* @param patchFlag - Optimization flag

137

* @param dynamicProps - Dynamic property names

138

* @returns Element block VNode

139

*/

140

function createElementBlock(

141

type: string,

142

props?: VNodeProps | null,

143

children?: VNodeArrayChildren,

144

patchFlag?: number,

145

dynamicProps?: string[]

146

): VNode;

147

```

148

149

**Usage Examples:**

150

151

```typescript

152

import {

153

createTextVNode,

154

createCommentVNode,

155

createStaticVNode,

156

createElementVNode,

157

createElementBlock

158

} from "@vue/runtime-core";

159

160

// Text node creation

161

const textNode = createTextVNode('Hello World');

162

const dynamicTextNode = createTextVNode(

163

'Dynamic text',

164

1 // PatchFlags.TEXT - indicates text content can change

165

);

166

167

// Comment nodes

168

const commentNode = createCommentVNode('This is a comment');

169

const blockComment = createCommentVNode('Block comment', true);

170

171

// Static content (hoisted by compiler)

172

const staticNode = createStaticVNode(

173

'<div class="static"><span>Static content</span></div>',

174

2 // Number of nodes in the static content

175

);

176

177

// Element nodes

178

const simpleElement = createElementVNode('div', { id: 'simple' });

179

180

const dynamicElement = createElementVNode(

181

'div',

182

{ class: 'dynamic' },

183

[textNode],

184

8, // PatchFlags.PROPS - indicates props can change

185

['class'] // Dynamic prop names

186

);

187

188

// Element blocks (with optimization tracking)

189

const elementBlock = createElementBlock(

190

'div',

191

{ class: 'block' },

192

[

193

createTextVNode('Block content'),

194

createElementVNode('span', null, 'Span content')

195

]

196

);

197

```

198

199

### Render List Helpers

200

201

Utilities for rendering lists efficiently.

202

203

```typescript { .api }

204

/**

205

* Renders a list of items with a render function

206

* @param source - Array, object, string, or number to iterate

207

* @param renderItem - Function to render each item

208

* @returns Array of VNodes

209

*/

210

function renderList<T>(

211

source: T[] | Record<string | number, T> | string | number,

212

renderItem: (value: T, key: string | number, index: number) => VNode

213

): VNode[];

214

```

215

216

**Usage Examples:**

217

218

```typescript

219

import { renderList, h } from "@vue/runtime-core";

220

221

// Array rendering

222

const items = ['apple', 'banana', 'cherry'];

223

const listNodes = renderList(items, (item, key, index) => {

224

return h('li', { key }, `${index}: ${item}`);

225

});

226

227

// Object rendering

228

const user = { name: 'John', age: 30, city: 'New York' };

229

const userInfoNodes = renderList(user, (value, key) => {

230

return h('div', { key }, `${key}: ${value}`);

231

});

232

233

// Number rendering (1 to n)

234

const numberNodes = renderList(5, (value, key) => {

235

return h('span', { key }, `Number ${value}`);

236

});

237

238

// String rendering (each character)

239

const charNodes = renderList('hello', (char, index) => {

240

return h('span', { key: index }, char);

241

});

242

243

// Complete list component

244

const ListComponent = defineComponent({

245

props: {

246

items: Array,

247

itemRenderer: Function

248

},

249

250

setup(props) {

251

return () => h('ul',

252

renderList(props.items || [], (item, index) => {

253

return props.itemRenderer

254

? props.itemRenderer(item, index)

255

: h('li', { key: index }, String(item));

256

})

257

);

258

}

259

});

260

```

261

262

### Slot Rendering Helpers

263

264

Utilities for rendering slots and slot content.

265

266

```typescript { .api }

267

/**

268

* Renders a slot with optional props and fallback content

269

* @param slots - Slots object

270

* @param name - Slot name

271

* @param props - Props to pass to slot

272

* @param fallback - Fallback content if slot is empty

273

* @returns VNode or array of VNodes

274

*/

275

function renderSlot(

276

slots: Slots,

277

name: string,

278

props?: Data,

279

fallback?: () => VNodeArrayChildren

280

): VNode;

281

282

/**

283

* Creates a slots object from slot definitions

284

* @param slots - Base slots object

285

* @param dynamicSlots - Dynamic slot descriptors

286

* @returns Complete slots object

287

*/

288

function createSlots(

289

slots: Record<string, Slot>,

290

dynamicSlots: (CompiledSlotDescriptor | CompiledSlotDescriptor[])[]

291

): Slots;

292

293

interface CompiledSlotDescriptor {

294

name: string;

295

fn: Slot;

296

key?: string | number;

297

}

298

```

299

300

**Usage Examples:**

301

302

```typescript

303

import { renderSlot, createSlots, h } from "@vue/runtime-core";

304

305

// Render slot with fallback

306

const SlotComponent = defineComponent({

307

setup(_, { slots }) {

308

return () => h('div', { class: 'wrapper' }, [

309

renderSlot(slots, 'header', {}, () => [

310

h('h1', 'Default Header')

311

]),

312

313

renderSlot(slots, 'default'),

314

315

renderSlot(slots, 'footer', { timestamp: Date.now() }, () => [

316

h('footer', 'Default Footer')

317

])

318

]);

319

}

320

});

321

322

// Dynamic slot creation

323

const DynamicSlotComponent = defineComponent({

324

props: {

325

slotConfigs: Array

326

},

327

328

setup(props, { slots }) {

329

return () => {

330

const dynamicSlots = props.slotConfigs?.map(config => ({

331

name: config.name,

332

fn: (props) => h('div', `Dynamic slot: ${config.name}`)

333

})) || [];

334

335

const allSlots = createSlots(slots, dynamicSlots);

336

337

return h('div',

338

Object.keys(allSlots).map(name =>

339

renderSlot(allSlots, name)

340

)

341

);

342

};

343

}

344

});

345

```

346

347

### Event Handler Helpers

348

349

Utilities for handling events and handler normalization.

350

351

```typescript { .api }

352

/**

353

* Converts event object to handler functions

354

* @param obj - Object with event handlers

355

* @returns Object with normalized handlers

356

*/

357

function toHandlers(obj: Record<string, any>): Record<string, Function | Function[]>;

358

```

359

360

**Usage Examples:**

361

362

```typescript

363

import { toHandlers, h } from "@vue/runtime-core";

364

365

// Convert event object to handlers

366

const EventComponent = defineComponent({

367

props: {

368

events: Object

369

},

370

371

setup(props) {

372

return () => {

373

const handlers = toHandlers(props.events || {});

374

375

return h('button', {

376

...handlers,

377

class: 'event-button'

378

}, 'Click me');

379

};

380

}

381

});

382

383

// Usage

384

const eventConfig = {

385

onClick: () => console.log('clicked'),

386

onMouseenter: () => console.log('mouse enter'),

387

onMouseleave: () => console.log('mouse leave')

388

};

389

390

h(EventComponent, { events: eventConfig });

391

392

// Multiple handlers for same event

393

const multiHandlerConfig = {

394

onClick: [

395

() => console.log('First handler'),

396

() => console.log('Second handler')

397

]

398

};

399

400

const multiHandlers = toHandlers(multiHandlerConfig);

401

// Results in: { onClick: [Function, Function] }

402

```

403

404

### Memoization Helpers

405

406

Utilities for memoizing render functions and expensive computations.

407

408

```typescript { .api }

409

/**

410

* Memoizes a render function based on dependencies

411

* @param memo - Dependency array for memoization

412

* @param render - Render function to memoize

413

* @param cache - Cache array for storing previous results

414

* @param index - Cache index for this memoization

415

* @returns Memoized result or new computation

416

*/

417

function withMemo<T>(

418

memo: any[],

419

render: () => T,

420

cache: any[],

421

index: number

422

): T;

423

424

/**

425

* Checks if memoization dependencies are the same

426

* @param cached - Previously cached dependencies

427

* @param memo - Current dependencies

428

* @returns True if dependencies are the same

429

*/

430

function isMemoSame(cached: any[], memo: any[]): boolean;

431

```

432

433

**Usage Examples:**

434

435

```typescript

436

import { withMemo, isMemoSame, h } from "@vue/runtime-core";

437

438

const MemoizedComponent = defineComponent({

439

props: {

440

items: Array,

441

processor: Function

442

},

443

444

setup(props) {

445

const cache: any[] = [];

446

447

return () => {

448

// Memoize expensive list processing

449

const processedItems = withMemo(

450

[props.items, props.processor], // Dependencies

451

() => {

452

console.log('Processing items...');

453

return props.items?.map(props.processor) || [];

454

},

455

cache, // Cache array

456

0 // Cache index

457

);

458

459

return h('ul',

460

processedItems.map((item, index) =>

461

h('li', { key: index }, item)

462

)

463

);

464

};

465

}

466

});

467

468

// Manual memoization check

469

const useMemoCheck = () => {

470

const lastDeps = ref<any[]>([]);

471

const lastResult = ref<any>(null);

472

473

const memoizedCompute = (deps: any[], computeFn: () => any) => {

474

if (!isMemoSame(lastDeps.value, deps)) {

475

lastResult.value = computeFn();

476

lastDeps.value = deps;

477

}

478

return lastResult.value;

479

};

480

481

return { memoizedCompute };

482

};

483

```

484

485

### Context and Scope Helpers

486

487

Utilities for managing render context and scoped CSS.

488

489

```typescript { .api }

490

/**

491

* Wraps a function with render context

492

* @param fn - Function to wrap

493

* @param ctx - Component context

494

* @returns Wrapped function

495

*/

496

function withCtx<T extends Function>(fn: T, ctx?: ComponentInternalInstance): T;

497

498

/**

499

* Pushes a scope ID for scoped CSS

500

* @param id - Scope ID to push

501

*/

502

function pushScopeId(id: string | null): void;

503

504

/**

505

* Pops the current scope ID

506

*/

507

function popScopeId(): void;

508

509

/**

510

* Wraps a function to run with a specific scope ID

511

* @param id - Scope ID to use

512

* @returns Function wrapper

513

*/

514

function withScopeId<T extends Function>(id: string): (fn: T) => T;

515

```

516

517

**Usage Examples:**

518

519

```typescript

520

import { withCtx, pushScopeId, popScopeId, withScopeId } from "@vue/runtime-core";

521

522

// Context wrapping

523

const ContextComponent = defineComponent({

524

setup() {

525

const instance = getCurrentInstance();

526

527

const wrappedHandler = withCtx(() => {

528

console.log('Handler called with context');

529

}, instance);

530

531

return () => h('button', { onClick: wrappedHandler }, 'Click');

532

}

533

});

534

535

// Scoped CSS management

536

const ScopedComponent = defineComponent({

537

setup() {

538

const scopeId = 'data-v-123abc';

539

540

return () => {

541

pushScopeId(scopeId);

542

543

const element = h('div', { class: 'scoped' }, [

544

h('span', 'Scoped content')

545

]);

546

547

popScopeId();

548

549

return element;

550

};

551

}

552

});

553

554

// Scope ID wrapper

555

const createScopedRenderer = (scopeId: string) => {

556

const withScope = withScopeId(scopeId);

557

558

return withScope((props: any) => {

559

return h('div', { class: 'scoped-component' }, props.children);

560

});

561

};

562

563

const ScopedRenderer = createScopedRenderer('data-v-456def');

564

```

565

566

## Advanced Usage Patterns

567

568

### Custom Render Pipeline

569

570

```typescript

571

// Custom render function with optimizations

572

const createOptimizedRenderer = () => {

573

const cache: any[] = [];

574

let blockStack: VNode[] = [];

575

576

const render = (component: any, props: any) => {

577

openBlock();

578

579

const vnode = withMemo(

580

[component, props],

581

() => {

582

setBlockTracking(1);

583

584

const result = createElementBlock(

585

'div',

586

{ class: 'optimized' },

587

[

588

createTextVNode('Optimized content'),

589

renderList(props.items || [], (item, index) =>

590

createElementVNode('span', { key: index }, item)

591

)

592

]

593

);

594

595

setBlockTracking(0);

596

return result;

597

},

598

cache,

599

0

600

);

601

602

return vnode;

603

};

604

605

return { render };

606

};

607

608

// Static hoisting simulation

609

const createHoistedContent = () => {

610

// This would typically be done by the compiler

611

const hoistedStatic = createStaticVNode(

612

'<div class="static-header"><h1>Static Title</h1></div>',

613

2

614

);

615

616

return (dynamicContent: VNode[]) => {

617

return createElementBlock('div', null, [

618

hoistedStatic,

619

...dynamicContent

620

]);

621

};

622

};

623

```

624

625

## Types

626

627

```typescript { .api }

628

interface Slots {

629

[name: string]: Slot | undefined;

630

}

631

632

type Slot<T = any> = (...args: any[]) => VNode[];

633

634

interface CompiledSlotDescriptor {

635

name: string;

636

fn: Slot;

637

key?: string | number;

638

}

639

640

type Data = Record<string, unknown>;

641

642

// Patch flags for optimization

643

enum PatchFlags {

644

TEXT = 1,

645

CLASS = 2,

646

STYLE = 4,

647

PROPS = 8,

648

FULL_PROPS = 16,

649

HYDRATE_EVENTS = 32,

650

STABLE_FRAGMENT = 64,

651

KEYED_FRAGMENT = 128,

652

UNKEYED_FRAGMENT = 256,

653

NEED_PATCH = 512,

654

DYNAMIC_SLOTS = 1024,

655

HOISTED = -1,

656

BAIL = -2

657

}

658

```

659

660

## Performance Considerations

661

662

### Block Tracking Benefits

663

664

1. **Selective Updates**: Only tracked dynamic children are diffed

665

2. **Skip Static Content**: Static content is completely skipped during updates

666

3. **Efficient Reconciliation**: Reduces the number of nodes to compare

667

668

### Memoization Guidelines

669

670

1. **Use for Expensive Operations**: Only memoize computationally expensive functions

671

2. **Dependency Management**: Keep dependency arrays minimal and specific

672

3. **Cache Management**: Consider cache size limits for long-running applications

673

674

### Static Hoisting

675

676

1. **Compiler Optimization**: Static content is hoisted outside render functions

677

2. **Memory Efficiency**: Static VNodes are created once and reused

678

3. **Performance Improvement**: Reduces VNode creation overhead