Install

vuejs/vue

Vue 2 Framework

Last updated on Oct 10, 2024 (Commit: 9e88707)

Overview

Relevant Files
  • README.md
  • package.json
  • src/core/index.ts
  • src/v3/index.ts
  • src/core/instance/index.ts
  • src/compiler/index.ts
  • src/platforms/web/runtime/index.ts

Vue 2 is a progressive JavaScript framework for building user interfaces. This repository contains the source code for Vue 2.7.16, the final version of Vue 2 before the framework reached End of Life on December 31st, 2023. While no longer actively maintained, Vue 2 remains available on all distribution channels and continues to power millions of applications worldwide.

What is Vue?

Vue is designed to be incrementally adoptable, scaling from a simple view library to a full-featured framework. It focuses on the view layer with an approachable core that handles reactive data binding, component composition, and DOM rendering. The framework is platform-agnostic at its core, supporting browser environments, Node.js server-side rendering, and embedded JavaScript runtimes.

Core Architecture

The codebase is organized into several key modules:

  • src/core - Platform-agnostic runtime containing the Vue instance, reactivity system, virtual DOM, and lifecycle management
  • src/compiler - Template parser, optimizer, and code generator that converts Vue templates into render functions
  • src/v3 - Composition API and modern reactivity utilities (ref, reactive, computed, watch, etc.)
  • src/platforms/web - Web-specific implementations including DOM patching, directives, and component mounting
  • src/shared - Shared utilities and constants used across the framework

Key Features

Vue 2 provides a complete reactive system where data changes automatically trigger UI updates. The framework uses a virtual DOM for efficient rendering and supports both the Options API (traditional component definition) and the Composition API (modern function-based approach). Built-in features include component lifecycle hooks, watchers, computed properties, directives, and transitions.

Build System

The project uses pnpm as the package manager and Rollup for bundling. Multiple distribution formats are generated:

  • CommonJS for Node.js environments
  • ES modules for modern bundlers
  • UMD builds for browser <script> tags
  • Server-side rendering builds

The build process is configured in scripts/config.js and executed via npm run build.

Composition API Integration

Vue 2.7 includes backported Composition API features from Vue 3, allowing developers to use modern patterns like ref(), reactive(), computed(), and watch() alongside traditional Options API code. This enables gradual migration paths for applications moving toward Vue 3.

Loading diagram...

Development vs. Production

The framework includes development-mode warnings and performance monitoring. Production builds are optimized for size and speed. The __DEV__ flag controls which code paths are included in each build, allowing development features to be tree-shaken in production.

Architecture & Core Systems

Relevant Files
  • src/core/instance/index.ts
  • src/core/observer/index.ts
  • src/core/observer/dep.ts
  • src/core/vdom/vnode.ts
  • src/core/vdom/patch.ts
  • src/compiler/index.ts
  • src/platforms/web/runtime/index.ts

Vue 2 is built on three core pillars: reactivity, virtual DOM, and component lifecycle. These systems work together to enable efficient, declarative UI updates.

Reactivity System

The reactivity system makes data changes automatically trigger UI updates. When you define data properties, Vue wraps them with getters and setters using Object.defineProperty(). The Observer class (in src/core/observer/index.ts) attaches itself to objects and converts properties into reactive getters/setters.

The Dep class (dependency) tracks which watchers depend on each property. When a property is accessed, the current watcher is recorded via Dep.target. When a property changes, all dependent watchers are notified and scheduled for updates. This creates a fine-grained reactivity system where only affected components re-render.

// Simplified reactivity flow
const dep = new Dep()
Object.defineProperty(obj, 'key', {
  get() {
    if (Dep.target) dep.depend()  // Track dependency
    return value
  },
  set(newVal) {
    value = newVal
    dep.notify()  // Notify all watchers
  }
})

Virtual DOM & Patching

Vue uses a virtual DOM (VNode tree) as an intermediate representation between components and the actual DOM. The VNode class represents a single node in this tree, storing tag names, data, children, and references to the actual DOM element.

When a component's data changes, Vue re-renders it to produce a new VNode tree. The patch function (in src/core/vdom/patch.ts) compares the old and new trees, identifying minimal DOM changes needed. This algorithm is based on Snabbdom and uses key-based reconciliation for efficient list updates.

Component Lifecycle

Vue components follow a well-defined lifecycle with hooks: beforeCreate, created, beforeMount, mounted, beforeUpdate, updated, beforeDestroy, destroyed. The lifecycleMixin function (in src/core/instance/lifecycle.ts) implements the _update method, which calls __patch__ to synchronize the VNode tree with the DOM.

Compilation Pipeline

Templates are compiled to render functions via the compiler (in src/compiler/index.ts). The pipeline has three stages:

  1. Parse: Template string → AST
  2. Optimize: Mark static nodes that never change
  3. Generate: AST → JavaScript render function code

The generated render function creates VNodes efficiently, with static nodes hoisted outside the function to avoid recreation.

Platform Integration

The web platform implementation (in src/platforms/web/runtime/index.ts) installs platform-specific utilities and the patch function. The $mount method queries the DOM element and calls mountComponent, which creates a watcher that re-renders whenever reactive data changes.

Loading diagram...

Reactivity System

Relevant Files
  • src/core/observer/dep.ts
  • src/core/observer/watcher.ts
  • src/core/observer/scheduler.ts
  • src/v3/reactivity/ref.ts
  • src/v3/reactivity/reactive.ts

Vue's reactivity system is the foundation for automatic UI updates. It tracks which data properties are accessed during rendering and automatically re-renders when those properties change. The system uses a dependency tracking model where watchers subscribe to observable properties.

Core Concepts

Dependency (Dep): A Dep object represents an observable property. It maintains a list of subscribers (watchers) that depend on it. When the property changes, the Dep notifies all subscribers.

Watcher: A Watcher collects dependencies by executing a getter function. During execution, any property access triggers the property's Dep.depend() method, which registers the watcher as a subscriber. When dependencies change, the watcher's update() method is called.

Observer: The Observer class wraps objects and converts their properties into getter/setter pairs. Getters track dependencies, and setters trigger notifications to all dependent watchers.

Dependency Tracking Flow

Loading diagram...

Scheduler and Batching

The scheduler prevents redundant updates by batching watchers. When a property changes, instead of immediately running all dependent watchers, they are queued. The scheduler then flushes the queue asynchronously (via nextTick), ensuring:

  1. Parent-to-child updates: Watchers are sorted by ID, so parent components update before children.
  2. Deduplication: Duplicate watcher IDs are skipped to avoid redundant work.
  3. Circular update detection: Prevents infinite loops by tracking update counts.

Ref and Reactive APIs

Ref: Wraps a single value in an object with a value property. The value property is made reactive using defineReactive(), which creates a Dep for tracking changes.

Reactive: Converts plain objects into reactive proxies by attaching an Observer. All nested properties become reactive automatically (deep reactivity by default).

Shallow variants: shallowRef() and shallowReactive() only track the root level, improving performance for large objects.

Key Implementation Details

  • Dep.target stack: Maintains a stack of active watchers to handle nested watchers correctly.
  • Cleanup: Watchers clean up old dependencies after each evaluation to prevent memory leaks.
  • Lazy evaluation: Computed properties use lazy watchers that only evaluate when accessed.
  • Custom refs: Allow fine-grained control over tracking and triggering via customRef().

Virtual DOM & Rendering

Relevant Files
  • src/core/vdom/create-element.ts
  • src/core/vdom/patch.ts
  • src/core/vdom/vnode.ts
  • src/core/instance/render.ts
  • src/core/vdom/create-component.ts

Overview

Vue's rendering system is built on a Virtual DOM (VDOM) architecture that decouples component logic from DOM operations. The system consists of three main phases: VNode creation, patching (diffing), and DOM updates. This design enables efficient updates, cross-platform rendering, and powerful optimizations.

VNode Structure

A VNode is a lightweight JavaScript object representing a DOM element, text node, or component. The VNode class in src/core/vdom/vnode.ts contains:

  • Core properties: tag (element name), data (attributes/events), children (child vnodes), text (text content)
  • DOM reference: elm (actual DOM node after creation)
  • Component metadata: componentInstance, componentOptions, context
  • Optimization flags: isStatic, isCloned, isOnce, asyncFactory

VNodes are immutable during rendering—they represent a snapshot of the UI at a specific moment.

Element Creation

The createElement function in src/core/vdom/create-element.ts is the primary API for creating VNodes. It handles:

  1. Flexible argument handling: Detects if data is omitted and shifts parameters accordingly
  2. Child normalization: Converts nested arrays and functions into a flat VNode array
  3. Tag resolution: Distinguishes between HTML elements, registered components, and async components
  4. Namespace handling: Applies SVG/XML namespaces recursively to child elements
// Template: <div class="box">Hello</div>
// Compiles to:
createElement(vm, 'div', { class: 'box' }, 'Hello')

Patching Algorithm

The patch function in src/core/vdom/patch.ts is the core diffing engine. It compares old and new VNode trees and applies minimal DOM changes:

Loading diagram...

Key optimizations:

  • Vnode identity check: sameVnode() compares key, tag, and asyncFactory
  • Four-pointer algorithm: updateChildren() uses bidirectional pointers to minimize moves
  • Key-based reconciliation: Keyed elements are matched by identity, enabling reordering without recreation

Rendering Pipeline

The complete render-to-patch flow:

  1. _render() (in src/core/instance/render.ts): Calls the component's render function, returning a VNode tree
  2. _update() (in src/core/instance/lifecycle.ts): Calls __patch__() with the new VNode
  3. createElm(): Recursively creates DOM nodes from VNodes
  4. patchVnode(): Updates existing nodes by comparing old and new VNodes
  5. Hooks invoked: create, update, insert, destroy hooks run at appropriate lifecycle points

Component Mounting

Component VNodes trigger special initialization via hooks in src/core/vdom/create-component.ts:

  • init hook: Creates a component instance and calls $mount()
  • prepatch hook: Updates props, listeners, and children on re-render
  • insert hook: Fires the mounted lifecycle hook after DOM insertion

This separation allows components to be lazy-loaded, kept-alive, or dynamically created without blocking the patch process.

Hydration

Server-rendered HTML is matched to VNodes via the hydrate() function. It walks the DOM tree and associates existing elements with VNodes, avoiding unnecessary recreation. This enables fast initial page loads with server-side rendering.

Template Compiler

Relevant Files
  • src/compiler/index.ts
  • src/compiler/parser/index.ts
  • src/compiler/optimizer.ts
  • src/compiler/codegen/index.ts
  • src/compiler/create-compiler.ts

The template compiler transforms Vue template strings into executable JavaScript render functions. It's the core engine that converts declarative HTML-like syntax into imperative code that creates and updates the virtual DOM.

Compilation Pipeline

The compiler follows a three-stage pipeline:

Loading diagram...

Each stage is independent and can be customized via createCompilerCreator, enabling variants like the SSR-optimizing compiler.

Stage 1: Parsing

The parser converts template HTML into an Abstract Syntax Tree (AST). It uses parseHTML to tokenize the template and builds an ASTElement tree while processing Vue-specific syntax:

  • Directives (v-if, v-for, v-bind, etc.) are parsed and attached to elements
  • Attributes are categorized as static, dynamic, or properties
  • Event handlers and modifiers are extracted
  • Slots and scoped slots are identified
  • Text interpolations (\{\{ expression \}\}) are parsed into expressions

The parser is highly configurable via CompilerOptions, allowing platform-specific behavior (e.g., which tags are reserved, how to handle namespaces).

Stage 2: Optimization

The optimizer walks the AST and marks subtrees that are purely static (never change). This enables two critical optimizations:

  1. Hoisting: Static subtrees are extracted into constants, avoiding re-creation on every render
  2. Skipping: Static nodes are completely skipped during the patching process

The optimizer runs in two passes:

  • First pass: Mark all non-static nodes by checking for bindings, directives, or dynamic content
  • Second pass: Identify static roots (static nodes with non-text children) that benefit from hoisting

Static analysis respects component boundaries—slot content is never marked static to allow mutation and hot-reloading.

Stage 3: Code Generation

The code generator recursively traverses the optimized AST and emits JavaScript code. It generates:

  • Render function: Main function that creates the virtual DOM tree using _c() (createElement)
  • Static render functions: Separate functions for hoisted static subtrees, called once and cached

The generator handles special cases:

  • Conditional rendering (v-if/v-else) → _c() calls wrapped in ternary operators
  • List rendering (v-for) → _l() (renderList) calls with iteration logic
  • Components → Dynamic component resolution with binding metadata
  • Slots_t() (renderSlot) calls with scope data
  • Events & bindings → Inline event handlers and dynamic attribute objects

Key Data Structures

ASTElement represents a DOM element or component in the tree:

  • type: 1 identifies it as an element node
  • tag, attrsList, attrsMap store element metadata
  • children contains child nodes (elements, text, or expressions)
  • static, staticRoot mark optimization opportunities
  • if, for, ref, directives store Vue-specific features

CompiledResult is the final output:

  • ast: The parsed AST for inspection or further processing
  • render: String of the main render function code
  • staticRenderFns: Array of static render function strings
  • errors, tips: Compilation diagnostics

Compiler Factory Pattern

createCompilerCreator enables creating custom compilers with alternative implementations. The default compiler uses the standard parser, optimizer, and code generator. The SSR compiler, for example, uses the same parser but a different optimizer and code generator optimized for string concatenation.

const { compile, compileToFunctions } = createCompiler(baseOptions)

The factory returns both compile() (returns AST and code strings) and compileToFunctions() (returns executable functions).

Composition API

Relevant Files
  • src/v3/apiSetup.ts
  • src/v3/apiWatch.ts
  • src/v3/apiLifecycle.ts
  • src/v3/reactivity/computed.ts
  • src/v3/reactivity/ref.ts
  • src/v3/reactivity/reactive.ts

The Composition API is Vue 2's function-based alternative to the Options API, enabling better code organization and reusability through composable functions. It provides a set of low-level APIs for managing state, side effects, and lifecycle within the setup() function.

Core Concepts

Setup Function: The entry point for the Composition API. It receives props and a SetupContext object, and returns either a render function or an object of bindings exposed to the template.

export interface SetupContext {
  attrs: Record<string, any>
  listeners: Record<string, Function | Function[]>
  slots: Record<string, () => VNode[]>
  emit: (event: string, ...args: any[]) => any
  expose: (exposed: Record<string, any>) => void
}

The setup() function is invoked before component creation, with the current instance available via currentInstance for accessing lifecycle hooks and other APIs.

Reactivity Primitives

Ref: Wraps a value to make it reactive. Access the value via the .value property.

const count = ref(0)
count.value++ // reactive update

Reactive: Converts an object into a deeply reactive proxy. Automatically unwraps nested refs.

const state = reactive({ count: 0, name: 'Vue' })
state.count++ // reactive update

Computed: Creates a derived reactive value with lazy evaluation and caching.

const doubled = computed(() => count.value * 2)
const writable = computed({
  get: () => count.value,
  set: (v) => { count.value = v }
})

Watchers

watch(): Observes one or more reactive sources and runs a callback when they change.

watch(count, (newVal, oldVal) => {
  console.log(`Count changed from ${oldVal} to ${newVal}`)
})

watch([count, name], ([newCount, newName]) => {
  // handle multiple sources
})

watchEffect(): Automatically tracks dependencies and re-runs when they change. No callback needed.

watchEffect(() => {
  console.log(`Count is now ${count.value}`)
})

Options include immediate, deep, and flush ('pre', 'post', 'sync') to control timing and behavior.

Lifecycle Hooks

Composition API lifecycle hooks are functions called within setup() to register callbacks at specific component stages.

onBeforeMount(() => { /* ... */ })
onMounted(() => { /* ... */ })
onBeforeUpdate(() => { /* ... */ })
onUpdated(() => { /* ... */ })
onBeforeUnmount(() => { /* ... */ })
onUnmounted(() => { /* ... */ })

Additional hooks: onActivated, onDeactivated, onServerPrefetch, onRenderTracked, onRenderTriggered, and onErrorCaptured.

Context Helpers

useSlots(), useAttrs(), useListeners(): Access component slots, attributes, and event listeners from within setup().

const slots = useSlots()
const attrs = useAttrs()
const listeners = useListeners() // Vue 2 only

These helpers provide reactive proxies that sync with the component instance, enabling dynamic access to passed-in content and attributes.

Dependency Injection

provide() and inject(): Enable ancestor-to-descendant data passing without prop drilling.

provide('key', value)
const injected = inject('key', defaultValue)

Useful for plugin configuration and cross-component communication in deeply nested component trees.

Component Lifecycle & Initialization

Relevant Files
  • src/core/instance/init.ts
  • src/core/instance/lifecycle.ts
  • src/core/instance/state.ts
  • src/core/instance/events.ts
  • src/core/instance/render.ts

Component initialization in Vue follows a carefully orchestrated sequence that sets up all reactive systems, event handlers, and lifecycle hooks. Understanding this flow is critical for debugging and extending Vue's core behavior.

Initialization Sequence

When a component is instantiated via _init(), the following steps occur in strict order:

  1. Setup Phase - Assign unique ID, create effect scope, merge options
  2. Proxy Setup - Initialize render proxy for template access
  3. Lifecycle Initialization - Establish parent-child relationships
  4. Events Initialization - Set up event system
  5. Render Initialization - Configure render functions and slots
  6. beforeCreate Hook - Called before any state is initialized
  7. Injections - Resolve provide/inject dependencies
  8. State Initialization - Initialize props, data, computed, methods, watchers
  9. Provide - Set up provide for child components
  10. created Hook - Called after all state is ready
  11. Mount - If el option exists, automatically mount to DOM
// From init.ts - The _init method orchestrates this sequence
vm._uid = uid++
vm._isVue = true
vm._scope = new EffectScope(true)
initLifecycle(vm)
initEvents(vm)
initRender(vm)
callHook(vm, 'beforeCreate')
initInjections(vm)
initState(vm)
initProvide(vm)
callHook(vm, 'created')
if (vm.$options.el) vm.$mount(vm.$options.el)

State Initialization Details

The initState() function sets up all reactive properties in this order:

  • Props - Validated and made reactive via shallowReactive()
  • Setup - Composition API setup function (if present)
  • Methods - Bound to component instance
  • Data - Observed for deep reactivity
  • Computed - Lazy watchers created for each computed property
  • Watchers - User-defined watchers initialized

Props are intentionally initialized before data to allow data functions to reference props. Computed properties use lazy evaluation—they only compute when accessed.

Lifecycle Hooks Execution

Loading diagram...

Mounting and Updates

The mountComponent() function creates a render watcher that automatically triggers updates when reactive dependencies change. The watcher calls beforeUpdate before each update and updated after patching completes.

When a component is destroyed via $destroy(), the sequence reverses: beforeDestroy hook fires, the effect scope stops (cleaning up watchers), the virtual tree is patched to null, and finally the destroyed hook is called.

Key Internal Properties

  • _uid - Unique identifier for performance tracking
  • _scope - EffectScope for managing reactive effects
  • _vnode - Current virtual node representation
  • _watcher - The render watcher that drives updates
  • _isMounted - Flag indicating mount completion
  • _isDestroyed - Flag indicating destruction state
  • $options - Merged component options
  • $parent, $root, $children - Component tree references

Build Targets & Platform Integration

Relevant Files
  • scripts/config.js
  • scripts/build.js
  • src/platforms/web/entry-runtime.ts
  • src/platforms/web/entry-runtime-with-compiler.ts
  • packages/server-renderer/src/index.ts

Vue.js is distributed in multiple build formats to support different consumption patterns. The build system uses Rollup to generate optimized bundles for browsers, bundlers, and server-side rendering.

Build Targets Overview

The build configuration in scripts/config.js defines 20+ distinct build targets, each tailored for specific use cases:

Runtime-Only Builds include just the Vue runtime without the template compiler. These are smaller and faster, ideal for pre-compiled templates.

Full Builds bundle the runtime with the template compiler, enabling dynamic template compilation in the browser. This adds significant size but provides flexibility.

Module Formats determine how the code is packaged:

  • CommonJS (CJS) – Used by Node.js and bundlers like Webpack. Outputs to dist/vue.runtime.common.js and dist/vue.common.js.
  • ES Modules (ESM) – Modern JavaScript modules for bundlers. Outputs to dist/vue.runtime.esm.js and dist/vue.esm.js.
  • UMD – Universal Module Definition for direct browser inclusion via &lt;script&gt; tags. Outputs to dist/vue.js and dist/vue.runtime.js.

Environment Variants include development and production builds. Development builds include warnings and debug information. Production builds are minified using Terser with aggressive optimizations.

Entry Points

Each build target has a corresponding entry point in src/platforms/web/:

  • entry-runtime.ts – Runtime-only base (CommonJS & UMD)
  • entry-runtime-esm.ts – Runtime-only with named exports (ESM)
  • entry-runtime-with-compiler.ts – Full build base (CommonJS & UMD)
  • entry-runtime-with-compiler-esm.ts – Full build with named exports (ESM)
  • entry-compiler.ts – Standalone template compiler

These entry points extend the base Vue instance with Composition API utilities and expose the compiler when needed.

Server-Side Rendering

The packages/server-renderer/src/index.ts module provides createRenderer() and createBundleRenderer() functions for rendering Vue components to HTML strings on the server. It uses an optimized SSR compiler that pre-processes templates for server output.

Build Process

The scripts/build.js script orchestrates the build pipeline:

  1. Loads all build configurations from config.js
  2. Filters targets based on command-line arguments
  3. Runs Rollup for each target sequentially
  4. Minifies production builds with Terser
  5. Writes output files to dist/ and packages/*/

Common build commands:

  • npm run build – Build all targets
  • npm run build:ssr – Build runtime-cjs and server-renderer only
  • npm run dev – Watch mode for full-dev target
  • npm run dev:cjs – Watch mode for CommonJS runtime

Platform Integration

The src/platforms/web/ directory contains all web-specific code. The build system uses TypeScript compilation with platform-aware target settings: browser builds target ES5 for compatibility, while Node.js builds target ES2017.

The package.json exports field defines the entry points for different module systems, allowing consumers to import the appropriate build format automatically based on their environment.

Server-Side Rendering

Relevant Files
  • packages/server-renderer/src/render.ts
  • packages/server-renderer/src/create-basic-renderer.ts
  • packages/server-renderer/src/create-renderer.ts
  • packages/server-renderer/src/render-context.ts
  • packages/server-renderer/src/template-renderer/index.ts
  • packages/server-renderer/src/render-stream.ts

Server-Side Rendering (SSR) converts Vue components into HTML strings on the server, enabling faster initial page loads and better SEO. The system uses a state machine approach with streaming support for efficient rendering of large component trees.

Core Architecture

The SSR pipeline consists of three main layers:

  1. Render Function (render.ts): Traverses the component tree and converts VNodes to HTML strings
  2. Render Context (render-context.ts): Manages rendering state and coordinates async operations
  3. Template Renderer (template-renderer/index.ts): Wraps rendered content with HTML templates and injects assets
Loading diagram...

Rendering Pipeline

The rendering process follows a state machine pattern:

  1. Component Normalization: Templates are compiled to render functions if needed
  2. Server Prefetch: Async serverPrefetch hooks are awaited before rendering
  3. Node Traversal: Each VNode type (component, element, text) is rendered recursively
  4. State Stack: Render states track elements, fragments, and components for async handling
// Example: renderNode dispatches based on VNode type
if (node.isString) {
  renderStringNode(node, context)
} else if (isDef(node.componentOptions)) {
  renderComponent(node, isRoot, context)
} else if (isDef(node.tag)) {
  renderElement(node, isRoot, context)
}

Caching Strategy

Components can implement serverCacheKey to enable server-side caching:

  • Cache Hit: Cached HTML is reused; component lifecycle hooks are skipped
  • Cache Miss: Component renders normally; result is stored with _ssrRegister callbacks
  • Nested Caching: Parent and child caches merge results automatically

The cache requires get and set methods; optional has method optimizes lookups.

Streaming Rendering

RenderStream extends Node.js Readable for progressive HTML delivery:

  • Buffers rendered content until requested size is reached
  • Calls _read(n) to pull chunks of size n
  • Defers rendering continuation to prevent stack overflow (>800 depth)
  • Emits beforeEnd event before final flush

Template Injection

TemplateRenderer wraps rendered content with:

  • Resource Hints: Preload/prefetch links for critical assets
  • Styles: CSS files and inline component styles
  • State: Initial app state serialized as window.__INITIAL_STATE__
  • Scripts: Deferred script tags for client hydration

The clientManifest maps component IDs to bundle chunks for automatic async chunk injection.

Key Patterns

Async Handling: The next() method in RenderContext processes the render state stack, deferring continuation when stack depth exceeds 800 to prevent overflow.

Directive Processing: Directives like v-show are resolved from parent to child during SSR, with special handling for component root elements.

Scope ID Attachment: Scoped CSS IDs are attached to root elements for style isolation during SSR.

TypeScript Type Definitions

Relevant Files
  • types/index.d.ts
  • types/vue.d.ts
  • types/vnode.d.ts
  • types/options.d.ts
  • types/common.d.ts
  • types/plugin.d.ts
  • types/v3-component-options.d.ts

Vue 2 provides comprehensive TypeScript type definitions that enable full type safety for Vue applications. The type system covers components, virtual nodes, options, and the Vue instance itself, supporting both Vue 2 and Vue 3 Composition API patterns.

Core Type Structure

The type definitions are organized into several key modules:

  • vue.d.ts - Defines the main Vue interface and VueConstructor class, including instance properties ($data, $props, $el, $refs) and lifecycle methods ($mount, $destroy, $watch).
  • vnode.d.ts - Defines virtual node types (VNode, VNodeData, VNodeChildren) used by the rendering system.
  • options.d.ts - Defines component options types (Component, ComponentOptions, AsyncComponent) for Options API.
  • v3-component-options.d.ts - Defines Composition API types (SetupFunction, ComputedOptions, MethodOptions).
  • common.d.ts - Provides utility types like UnionToIntersection, HasDefined, and IfAny for advanced type manipulation.

Vue Instance and Constructor

The Vue interface represents a component instance with reactive data, computed properties, and lifecycle hooks. The VueConstructor interface provides static methods for global registration and configuration:

interface Vue<Data, Props, Instance, Options, Emit> {
  readonly $data: Data
  readonly $props: Props
  readonly $el: Element
  readonly $refs: Record<string, any>
  $watch(expOrFn: string, callback: Function): () => void
  $mount(elementOrSelector?: Element | string): this
}

interface VueConstructor<V extends Vue = Vue> {
  new (options?: ComponentOptions<V>): V
  extend(options?: ComponentOptions<V>): ExtendedVue<V, {}, {}, {}, {}, {}>
  component(id: string, definition?: ComponentOptions<V>): ExtendedVue<V, {}, {}, {}, {}, {}>
  use(plugin: PluginObject | PluginFunction, options?: any): VueConstructor<V>
}

Component Options and Props

Component options are typed through ComponentOptions, which accepts generic parameters for data, methods, computed properties, and props. Props can be defined as either an array of strings or an object with detailed type information:

type Component<Data, Methods, Computed, Props, SetupBindings> =
  | typeof Vue
  | FunctionalComponentOptions<Props>
  | ComponentOptions<never, Data, Methods, Computed, Props, SetupBindings>

type AsyncComponent<Data, Methods, Computed, Props, SetupBindings> =
  | AsyncComponentPromise<Data, Methods, Computed, Props, SetupBindings>
  | AsyncComponentFactory<Data, Methods, Computed, Props, SetupBindings>

Virtual Node System

Virtual nodes represent the rendered output. VNode contains metadata about DOM elements or components, while VNodeData holds attributes, event listeners, and styling:

interface VNode {
  tag?: string
  data?: VNodeData
  children?: VNode[]
  text?: string
  elm?: Node
  context?: Vue
  componentInstance?: Vue
}

interface VNodeData {
  key?: string | number
  class?: any
  style?: StyleValue
  props?: Record<string, any>
  attrs?: Record<string, any>
  on?: Record<string, Function | Function[]>
  ref?: VNodeRef
}

Composition API Integration

Vue 2 includes types for the Composition API through SetupFunction, which receives props and context, returning reactive bindings or a render function:

type SetupFunction<Props, RawBindings, Emits> = (
  this: void,
  props: Readonly<Props>,
  ctx: SetupContext<Emits>
) => RawBindings | (() => VNode | null) | void

Plugin System

Plugins extend Vue functionality through the PluginObject or PluginFunction interfaces:

type PluginFunction<T> = (Vue: typeof Vue, options?: T) => void

interface PluginObject<T> {
  install: PluginFunction<T>
  [key: string]: any
}

Type Inference and Utilities

The type system uses advanced TypeScript patterns for type inference. Utility types like ExtractPropTypes, ExtractDefaultPropTypes, and CombinedVueInstance automatically infer component instance types from options, enabling IDE autocomplete and compile-time type checking.