Core compiler for Vue.js template compilation and transformation
—
Vue Compiler Core's transform system provides a flexible plugin architecture for processing and modifying AST nodes. The system includes built-in transforms for Vue directives, structural elements, and optimizations, as well as extensibility for custom transforms.
The central context object that manages transformation state and provides utilities.
/**
* Context object passed through all transformations
*/
interface TransformContext {
/** Root AST node being transformed */
root: RootNode;
/** Map of runtime helpers to usage count */
helpers: Map<symbol, number>;
/** Set of component names referenced */
components: Set<string>;
/** Set of directive names referenced */
directives: Set<string>;
/** Array of hoisted expressions */
hoists: (JSChildNode | null)[];
/** Import statements needed */
imports: ImportItem[];
/** Cache for constant expressions */
constantCache: WeakMap<TemplateChildNode, ConstantTypes>;
/** Number of temporary variables */
temps: number;
/** Number of cached expressions */
cached: number;
/** Identifier tracking for scoping */
identifiers: { [name: string]: number | undefined };
/** Scope counters for different directive types */
scopes: {
vFor: number;
vSlot: number;
vPre: number;
vOnce: number;
};
/** Current parent node */
parent: ParentNode | null;
/** Index of current node in parent's children */
childIndex: number;
/** Current node being processed */
currentNode: RootNode | TemplateChildNode | null;
/** Whether currently inside v-once */
inVOnce: boolean;
/** Add a runtime helper and return its name */
helper(name: symbol): string;
/** Remove a runtime helper */
removeHelper(name: symbol): void;
/** Get string representation of helper */
helperString(name: symbol): string;
/** Replace the current node */
replaceNode(node: TemplateChildNode): void;
/** Remove the current node */
removeNode(node?: TemplateChildNode): void;
/** Callback when node is removed */
onNodeRemoved: (() => void) | undefined;
/** Add identifiers to scope tracking */
addIdentifiers(exp: ExpressionNode | string): void;
/** Remove identifiers from scope tracking */
removeIdentifiers(exp: ExpressionNode | string): void;
/** Hoist an expression for static optimization */
hoist(exp: string | JSChildNode | ArrayExpression): SimpleExpressionNode;
/** Cache an expression */
cache<T extends JSChildNode>(exp: T, isVNode?: boolean): CacheExpression | T;
}
/**
* Creates a new transform context
*/
function createTransformContext(
root: RootNode,
options: TransformOptions
): TransformContext;Core functions for applying transformations to AST nodes.
/**
* Traverses and transforms a single AST node and its children
* @param node - AST node to process
* @param context - Transform context
*/
function traverseNode(
node: RootNode | TemplateChildNode,
context: TransformContext
): void;
/**
* Creates a structural directive transform
* @param name - Directive name or pattern to match
* @param fn - Transform function to apply
* @returns Node transform function
*/
function createStructuralDirectiveTransform(
name: string | RegExp,
fn: StructuralDirectiveTransform
): NodeTransform;Usage Examples:
import {
createTransformContext,
traverseNode,
createStructuralDirectiveTransform
} from "@vue/compiler-core";
// Create transform context
const context = createTransformContext(ast, {
nodeTransforms: [/* transforms */],
directiveTransforms: {/* directive transforms */}
});
// Traverse and transform nodes
traverseNode(ast, context);
// Create custom structural directive transform
const customIfTransform = createStructuralDirectiveTransform(
'custom-if',
(node, dir, context) => {
// Transform logic here
}
);Type definitions for different kinds of transform functions.
/**
* Node transform function signature
*/
type NodeTransform = (
node: RootNode | TemplateChildNode,
context: TransformContext
) => void | (() => void) | (() => void)[];
/**
* Directive transform function signature
*/
type DirectiveTransform = (
dir: DirectiveNode,
node: ElementNode,
context: TransformContext,
augmentor?: (ret: DirectiveTransformResult) => DirectiveTransformResult
) => DirectiveTransformResult;
/**
* Structural directive transform function signature
*/
type StructuralDirectiveTransform = (
node: ElementNode,
dir: DirectiveNode,
context: TransformContext
) => void | (() => void);
/**
* Hoist transform function signature
*/
type HoistTransform = (
children: TemplateChildNode[],
context: TransformContext,
parent: ParentNode
) => void;Pre-built transforms for Vue's core directives.
Handles two-way data binding transformation.
/**
* Transform for v-model directive
*/
const transformModel: DirectiveTransform;Usage Examples:
// Template: <input v-model="value" />
// Transforms to: <input :modelValue="value" @update:modelValue="value = $event" />
// Custom v-model transform in directive transforms map
const directiveTransforms = {
model: transformModel
};Handles event listener transformation.
/**
* Transform for v-on directive
*/
const transformOn: DirectiveTransform;Usage Examples:
// Template: <button v-on:click="handler" />
// Template: <button @click="handler" />
// Transforms to event listener binding
const directiveTransforms = {
on: transformOn
};Handles attribute and property binding.
/**
* Transform for v-bind directive
*/
const transformBind: DirectiveTransform;Usage Examples:
// Template: <div v-bind:class="classes" />
// Template: <div :class="classes" />
// Transforms to property binding
const directiveTransforms = {
bind: transformBind
};Placeholder transform for directives that don't need processing.
/**
* No-operation directive transform
*/
const noopDirectiveTransform: DirectiveTransform;Functions for handling structural directives like v-if and v-for.
Handles conditional rendering transformation.
/**
* Processes v-if structural directive
* @param node - Element node with v-if
* @param branch - If branch node
* @param context - Transform context
*/
function processIf(
node: ElementNode,
branch: IfBranchNode,
context: TransformContext,
processCodegen?: (node: IfNode, branch: IfBranchNode, isRoot: boolean) => () => void
): () => void;Usage Examples:
// Template: <div v-if="condition">Content</div>
// Processes into conditional render structure
import { processIf } from "@vue/compiler-core";
// Used within node transforms to handle v-if
const ifTransform: NodeTransform = (node, context) => {
if (node.type === NodeTypes.ELEMENT && hasDirective(node, 'if')) {
return processIf(node, branch, context);
}
};Handles list rendering transformation.
/**
* Processes v-for structural directive
* @param node - Element node with v-for
* @param context - Transform context
*/
function processFor(
node: ElementNode,
context: TransformContext,
processCodegen?: (forNode: ForNode, child: ElementNode, context: TransformContext) => (() => void) | undefined
): (() => void) | undefined;
/**
* Creates parameters for v-for loops
* @param parseResult - Parsed v-for expression
* @param context - Transform context
*/
function createForLoopParams(
parseResult: ForParseResult,
context: TransformContext
): ExpressionNode[];Usage Examples:
// Template: <li v-for="item in items" :key="item.id">{{ item.name }}</li>
// Processes into render list structure
import { processFor, createForLoopParams } from "@vue/compiler-core";
// Used within node transforms to handle v-for
const forTransform: NodeTransform = (node, context) => {
if (node.type === NodeTypes.ELEMENT && hasDirective(node, 'for')) {
return processFor(node, context);
}
};Functions for handling JavaScript expressions within templates.
Main transform for processing JavaScript expressions.
/**
* Node transform for JavaScript expressions
*/
const transformExpression: NodeTransform;
/**
* Processes JavaScript expressions in templates
* @param node - Expression node to process
* @param context - Transform context
* @param asParams - Whether to treat as function parameters
* @param asRawStatements - Whether to treat as raw statements
* @param localVars - Local variable context
*/
function processExpression(
node: SimpleExpressionNode,
context: TransformContext,
asParams?: boolean,
asRawStatements?: boolean,
localVars?: Record<string, number>
): ExpressionNode;
/**
* Stringifies expressions for static analysis
* @param exp - Expression to stringify
*/
function stringifyExpression(exp: ExpressionNode | string): string;Usage Examples:
import { transformExpression, processExpression } from "@vue/compiler-core";
// Include in node transforms for expression processing
const nodeTransforms = [
transformExpression, // Handles {{ expressions }} and directive values
// ... other transforms
];
// Manual expression processing
const processedExp = processExpression(simpleExp, context);Functions for handling Vue slots and scoped slots.
Functions for constructing slot expressions.
/**
* Builds slot expressions from v-slot directives
* @param node - Element node with slots
* @param context - Transform context
* @param buildSlotFn - Function to build individual slots
*/
function buildSlots(
node: ElementNode,
context: TransformContext,
buildSlotFn?: SlotFnBuilder
): SlotsExpression;
/**
* Function signature for building individual slot functions
*/
type SlotFnBuilder = (
slotProps: ExpressionNode | undefined,
slotChildren: TemplateChildNode[],
loc: SourceLocation
) => FunctionExpression;
/**
* Processes slot outlet elements (<slot> tags)
* @param node - Slot outlet node
* @param context - Transform context
* @returns Slot name and props information
*/
function processSlotOutlet(
node: SlotOutletNode,
context: TransformContext
): { slotName: string | ExpressionNode; slotProps: PropsExpression | undefined };
/**
* Tracks v-for scope variables in slots
*/
const trackVForSlotScopes: NodeTransform;
/**
* Tracks slot scope variables
*/
const trackSlotScopes: NodeTransform;Usage Examples:
import { buildSlots, trackVForSlotScopes, trackSlotScopes } from "@vue/compiler-core";
// Include slot tracking in transforms
const nodeTransforms = [
trackSlotScopes,
trackVForSlotScopes,
// ... other transforms
];
// Build slots for component
const slots = buildSlots(componentNode, context);Functions for processing element nodes and component resolution.
Main transform for element processing.
/**
* Main node transform for element processing
*/
const transformElement: NodeTransform;
/**
* Resolves component names to runtime references
* @param node - Element node
* @param context - Transform context
* @param ssr - Whether in SSR mode
*/
function resolveComponentType(
node: ElementNode,
context: TransformContext,
ssr?: boolean
): string | symbol;
/**
* Builds props expression from attributes and directives
* @param node - Element node
* @param context - Transform context
* @param props - Props array to process
* @param ssr - Whether in SSR mode
*/
function buildProps(
node: ElementNode,
context: TransformContext,
props?: ElementNode['props'],
ssr?: boolean
): PropsExpression | undefined;
/**
* Builds directive arguments array
* @param props - Props array containing directives
* @param context - Transform context
*/
function buildDirectiveArgs(
props: ElementNode['props'],
context: TransformContext
): DirectiveArguments | undefined;
/**
* Type for props expressions
*/
type PropsExpression = ObjectExpression | CallExpression | ExpressionNode;Function for processing slot outlet elements.
/**
* Processes slot outlet elements (<slot>)
* @param node - Slot outlet element
* @param context - Transform context
*/
function processSlotOutlet(
node: ElementNode,
context: TransformContext
): void;Function for determining constant types for optimization.
/**
* Determines if a node can be statically analyzed and cached
* @param node - AST node to analyze
* @param context - Transform context
*/
function getConstantType(
node: TemplateChildNode | TemplateChildNode[],
context: TransformContext
): ConstantTypes;Types for transform function results.
/**
* Result of directive transform
*/
interface DirectiveTransformResult {
/** Generated props */
props: Property[];
/** Whether this directive needs runtime */
needRuntime?: boolean | symbol;
/** SSR-specific properties */
ssrTagParts?: TemplateLiteral['elements'];
}
/**
* Import item for transform context
*/
interface ImportItem {
/** Expression to import */
exp: string | ExpressionNode;
/** Path to import from */
path: string;
}import { type NodeTransform, NodeTypes } from "@vue/compiler-core";
const customTransform: NodeTransform = (node, context) => {
if (node.type === NodeTypes.ELEMENT && node.tag === 'custom-element') {
// Transform custom elements
node.tag = 'div'; // Replace with div
return () => {
// Exit function called after children are processed
console.log('Custom element processed');
};
}
};import { type DirectiveTransform } from "@vue/compiler-core";
const customDirectiveTransform: DirectiveTransform = (dir, node, context) => {
if (dir.name === 'custom') {
return {
props: [
// Generate props for the directive
createObjectProperty('customProp', dir.exp || createSimpleExpression('true', true))
]
};
}
return { props: [] };
};Install with Tessl CLI
npx tessl i tessl/npm-vue--compiler-core