Vue.js 3 runtime core library providing foundational APIs for building custom renderers and managing reactive component systems
—
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.
Control Vue's block tracking system for optimized re-rendering.
/**
* Opens a new block for tracking dynamic children
* @param disableTracking - Whether to disable tracking for this block
*/
function openBlock(disableTracking?: boolean): void;
/**
* Creates a block VNode with tracked dynamic children
* @param type - Element type or component
* @param props - Element/component props
* @param children - Child nodes
* @param patchFlag - Optimization hints
* @param dynamicProps - Names of dynamic props
* @returns Block VNode
*/
function createBlock(
type: VNodeTypes,
props?: VNodeProps | null,
children?: VNodeArrayChildren,
patchFlag?: number,
dynamicProps?: string[]
): VNode;
/**
* Sets the block tracking value
* @param value - Positive number enables tracking, 0 or negative disables
*/
function setBlockTracking(value: number): void;Usage Examples:
import { openBlock, createBlock, setBlockTracking, h } from "@vue/runtime-core";
// Manual block creation (typically done by compiler)
const createOptimizedElement = () => {
openBlock();
return createBlock('div', { class: 'container' }, [
h('span', 'Static content'),
// Dynamic content will be tracked
h('span', { key: Math.random() }, 'Dynamic content')
]);
};
// Disable tracking for certain scenarios
const createUnoptimizedElement = () => {
setBlockTracking(-1); // Disable tracking
const element = h('div', [
h('span', 'This won\'t be optimized')
]);
setBlockTracking(1); // Re-enable tracking
return element;
};
// Conditional block tracking
const createConditionalBlock = (optimize: boolean) => {
if (optimize) {
openBlock();
return createBlock('div', null, [
// Children will be tracked for optimization
]);
} else {
return h('div', [
// Children won't be tracked
]);
}
};Low-level VNode creation functions for specific node types.
/**
* Creates a text VNode
* @param text - Text content
* @param flag - Patch flag for optimization
* @returns Text VNode
*/
function createTextVNode(text?: string, flag?: number): VNode;
/**
* Creates a comment VNode
* @param text - Comment content
* @param asBlock - Whether to create as block
* @returns Comment VNode
*/
function createCommentVNode(text?: string, asBlock?: boolean): VNode;
/**
* Creates a static VNode for hoisted content
* @param content - Static HTML content
* @param numberOfNodes - Number of nodes in the content
* @returns Static VNode
*/
function createStaticVNode(content: string, numberOfNodes: number): VNode;
/**
* Creates an element VNode
* @param type - Element tag name
* @param props - Element properties
* @param children - Child nodes
* @param patchFlag - Optimization flag
* @param dynamicProps - Dynamic property names
* @returns Element VNode
*/
function createElementVNode(
type: string,
props?: VNodeProps | null,
children?: VNodeArrayChildren,
patchFlag?: number,
dynamicProps?: string[]
): VNode;
/**
* Creates an element block VNode (with tracking)
* @param type - Element tag name
* @param props - Element properties
* @param children - Child nodes
* @param patchFlag - Optimization flag
* @param dynamicProps - Dynamic property names
* @returns Element block VNode
*/
function createElementBlock(
type: string,
props?: VNodeProps | null,
children?: VNodeArrayChildren,
patchFlag?: number,
dynamicProps?: string[]
): VNode;Usage Examples:
import {
createTextVNode,
createCommentVNode,
createStaticVNode,
createElementVNode,
createElementBlock
} from "@vue/runtime-core";
// Text node creation
const textNode = createTextVNode('Hello World');
const dynamicTextNode = createTextVNode(
'Dynamic text',
1 // PatchFlags.TEXT - indicates text content can change
);
// Comment nodes
const commentNode = createCommentVNode('This is a comment');
const blockComment = createCommentVNode('Block comment', true);
// Static content (hoisted by compiler)
const staticNode = createStaticVNode(
'<div class="static"><span>Static content</span></div>',
2 // Number of nodes in the static content
);
// Element nodes
const simpleElement = createElementVNode('div', { id: 'simple' });
const dynamicElement = createElementVNode(
'div',
{ class: 'dynamic' },
[textNode],
8, // PatchFlags.PROPS - indicates props can change
['class'] // Dynamic prop names
);
// Element blocks (with optimization tracking)
const elementBlock = createElementBlock(
'div',
{ class: 'block' },
[
createTextVNode('Block content'),
createElementVNode('span', null, 'Span content')
]
);Utilities for rendering lists efficiently.
/**
* Renders a list of items with a render function
* @param source - Array, object, string, or number to iterate
* @param renderItem - Function to render each item
* @returns Array of VNodes
*/
function renderList<T>(
source: T[] | Record<string | number, T> | string | number,
renderItem: (value: T, key: string | number, index: number) => VNode
): VNode[];Usage Examples:
import { renderList, h } from "@vue/runtime-core";
// Array rendering
const items = ['apple', 'banana', 'cherry'];
const listNodes = renderList(items, (item, key, index) => {
return h('li', { key }, `${index}: ${item}`);
});
// Object rendering
const user = { name: 'John', age: 30, city: 'New York' };
const userInfoNodes = renderList(user, (value, key) => {
return h('div', { key }, `${key}: ${value}`);
});
// Number rendering (1 to n)
const numberNodes = renderList(5, (value, key) => {
return h('span', { key }, `Number ${value}`);
});
// String rendering (each character)
const charNodes = renderList('hello', (char, index) => {
return h('span', { key: index }, char);
});
// Complete list component
const ListComponent = defineComponent({
props: {
items: Array,
itemRenderer: Function
},
setup(props) {
return () => h('ul',
renderList(props.items || [], (item, index) => {
return props.itemRenderer
? props.itemRenderer(item, index)
: h('li', { key: index }, String(item));
})
);
}
});Utilities for rendering slots and slot content.
/**
* Renders a slot with optional props and fallback content
* @param slots - Slots object
* @param name - Slot name
* @param props - Props to pass to slot
* @param fallback - Fallback content if slot is empty
* @returns VNode or array of VNodes
*/
function renderSlot(
slots: Slots,
name: string,
props?: Data,
fallback?: () => VNodeArrayChildren
): VNode;
/**
* Creates a slots object from slot definitions
* @param slots - Base slots object
* @param dynamicSlots - Dynamic slot descriptors
* @returns Complete slots object
*/
function createSlots(
slots: Record<string, Slot>,
dynamicSlots: (CompiledSlotDescriptor | CompiledSlotDescriptor[])[]
): Slots;
interface CompiledSlotDescriptor {
name: string;
fn: Slot;
key?: string | number;
}Usage Examples:
import { renderSlot, createSlots, h } from "@vue/runtime-core";
// Render slot with fallback
const SlotComponent = defineComponent({
setup(_, { slots }) {
return () => h('div', { class: 'wrapper' }, [
renderSlot(slots, 'header', {}, () => [
h('h1', 'Default Header')
]),
renderSlot(slots, 'default'),
renderSlot(slots, 'footer', { timestamp: Date.now() }, () => [
h('footer', 'Default Footer')
])
]);
}
});
// Dynamic slot creation
const DynamicSlotComponent = defineComponent({
props: {
slotConfigs: Array
},
setup(props, { slots }) {
return () => {
const dynamicSlots = props.slotConfigs?.map(config => ({
name: config.name,
fn: (props) => h('div', `Dynamic slot: ${config.name}`)
})) || [];
const allSlots = createSlots(slots, dynamicSlots);
return h('div',
Object.keys(allSlots).map(name =>
renderSlot(allSlots, name)
)
);
};
}
});Utilities for handling events and handler normalization.
/**
* Converts event object to handler functions
* @param obj - Object with event handlers
* @returns Object with normalized handlers
*/
function toHandlers(obj: Record<string, any>): Record<string, Function | Function[]>;Usage Examples:
import { toHandlers, h } from "@vue/runtime-core";
// Convert event object to handlers
const EventComponent = defineComponent({
props: {
events: Object
},
setup(props) {
return () => {
const handlers = toHandlers(props.events || {});
return h('button', {
...handlers,
class: 'event-button'
}, 'Click me');
};
}
});
// Usage
const eventConfig = {
onClick: () => console.log('clicked'),
onMouseenter: () => console.log('mouse enter'),
onMouseleave: () => console.log('mouse leave')
};
h(EventComponent, { events: eventConfig });
// Multiple handlers for same event
const multiHandlerConfig = {
onClick: [
() => console.log('First handler'),
() => console.log('Second handler')
]
};
const multiHandlers = toHandlers(multiHandlerConfig);
// Results in: { onClick: [Function, Function] }Utilities for memoizing render functions and expensive computations.
/**
* Memoizes a render function based on dependencies
* @param memo - Dependency array for memoization
* @param render - Render function to memoize
* @param cache - Cache array for storing previous results
* @param index - Cache index for this memoization
* @returns Memoized result or new computation
*/
function withMemo<T>(
memo: any[],
render: () => T,
cache: any[],
index: number
): T;
/**
* Checks if memoization dependencies are the same
* @param cached - Previously cached dependencies
* @param memo - Current dependencies
* @returns True if dependencies are the same
*/
function isMemoSame(cached: any[], memo: any[]): boolean;Usage Examples:
import { withMemo, isMemoSame, h } from "@vue/runtime-core";
const MemoizedComponent = defineComponent({
props: {
items: Array,
processor: Function
},
setup(props) {
const cache: any[] = [];
return () => {
// Memoize expensive list processing
const processedItems = withMemo(
[props.items, props.processor], // Dependencies
() => {
console.log('Processing items...');
return props.items?.map(props.processor) || [];
},
cache, // Cache array
0 // Cache index
);
return h('ul',
processedItems.map((item, index) =>
h('li', { key: index }, item)
)
);
};
}
});
// Manual memoization check
const useMemoCheck = () => {
const lastDeps = ref<any[]>([]);
const lastResult = ref<any>(null);
const memoizedCompute = (deps: any[], computeFn: () => any) => {
if (!isMemoSame(lastDeps.value, deps)) {
lastResult.value = computeFn();
lastDeps.value = deps;
}
return lastResult.value;
};
return { memoizedCompute };
};Utilities for managing render context and scoped CSS.
/**
* Wraps a function with render context
* @param fn - Function to wrap
* @param ctx - Component context
* @returns Wrapped function
*/
function withCtx<T extends Function>(fn: T, ctx?: ComponentInternalInstance): T;
/**
* Pushes a scope ID for scoped CSS
* @param id - Scope ID to push
*/
function pushScopeId(id: string | null): void;
/**
* Pops the current scope ID
*/
function popScopeId(): void;
/**
* Wraps a function to run with a specific scope ID
* @param id - Scope ID to use
* @returns Function wrapper
*/
function withScopeId<T extends Function>(id: string): (fn: T) => T;Usage Examples:
import { withCtx, pushScopeId, popScopeId, withScopeId } from "@vue/runtime-core";
// Context wrapping
const ContextComponent = defineComponent({
setup() {
const instance = getCurrentInstance();
const wrappedHandler = withCtx(() => {
console.log('Handler called with context');
}, instance);
return () => h('button', { onClick: wrappedHandler }, 'Click');
}
});
// Scoped CSS management
const ScopedComponent = defineComponent({
setup() {
const scopeId = 'data-v-123abc';
return () => {
pushScopeId(scopeId);
const element = h('div', { class: 'scoped' }, [
h('span', 'Scoped content')
]);
popScopeId();
return element;
};
}
});
// Scope ID wrapper
const createScopedRenderer = (scopeId: string) => {
const withScope = withScopeId(scopeId);
return withScope((props: any) => {
return h('div', { class: 'scoped-component' }, props.children);
});
};
const ScopedRenderer = createScopedRenderer('data-v-456def');// Custom render function with optimizations
const createOptimizedRenderer = () => {
const cache: any[] = [];
let blockStack: VNode[] = [];
const render = (component: any, props: any) => {
openBlock();
const vnode = withMemo(
[component, props],
() => {
setBlockTracking(1);
const result = createElementBlock(
'div',
{ class: 'optimized' },
[
createTextVNode('Optimized content'),
renderList(props.items || [], (item, index) =>
createElementVNode('span', { key: index }, item)
)
]
);
setBlockTracking(0);
return result;
},
cache,
0
);
return vnode;
};
return { render };
};
// Static hoisting simulation
const createHoistedContent = () => {
// This would typically be done by the compiler
const hoistedStatic = createStaticVNode(
'<div class="static-header"><h1>Static Title</h1></div>',
2
);
return (dynamicContent: VNode[]) => {
return createElementBlock('div', null, [
hoistedStatic,
...dynamicContent
]);
};
};interface Slots {
[name: string]: Slot | undefined;
}
type Slot<T = any> = (...args: any[]) => VNode[];
interface CompiledSlotDescriptor {
name: string;
fn: Slot;
key?: string | number;
}
type Data = Record<string, unknown>;
// Patch flags for optimization
enum PatchFlags {
TEXT = 1,
CLASS = 2,
STYLE = 4,
PROPS = 8,
FULL_PROPS = 16,
HYDRATE_EVENTS = 32,
STABLE_FRAGMENT = 64,
KEYED_FRAGMENT = 128,
UNKEYED_FRAGMENT = 256,
NEED_PATCH = 512,
DYNAMIC_SLOTS = 1024,
HOISTED = -1,
BAIL = -2
}Install with Tessl CLI
npx tessl i tessl/npm-vue--runtime-core