Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

Vue Core — Admin & Architecture Guide

Generated June 2026 from vuejs/core at 86ad076

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

This guide is for the people who build, ship, and contribute to Vue itself — maintainers, contributors, framework integrators, and architects who need to understand how the vuejs/core monorepo is structured, how it builds, and how its internals actually work. It is written from the source at version 3.5.35, commit 86ad076.

If you are using Vue to build an application, read the User Guide instead. This document assumes you are working on Vue or integrating its packages at a deep level.


1. Executive Summary

vuejs/core is a pnpm monorepo that produces the vue npm package and a family of @vue/* packages. The codebase is written in TypeScript, built with Rollup + esbuild, tested with Vitest, and organized so that each layer of the framework — reactivity, runtime, compiler, server renderer — is an independently publishable package with a clear dependency direction.

Property Value
Repository vuejs/core (the Vue 3 core)
Version 3.5.35
License MIT (© 2013–present, Yuxi "Evan" You)
Language TypeScript (compiled to ES2016 for browser builds, ES2019 for Node/SSR)
Package manager pnpm 11.3.0 (enforced via only-allow)
Module system ESM-first ("type": "module")
Build tool Rollup 4.x with rollup-plugin-esbuild; SWC for minification
Test runner Vitest 4.x (jsdom for DOM tests, Puppeteer for e2e)
Node requirement >= 20.0.0
Total source ~1.69M chars across 677 files, 42 high-priority source folders

The architectural throughline: the compiler turns templates into render functions; the reactivity system tracks state; the runtime renders and patches the DOM (or any custom target) in response to reactive change. Each concern is a separate package so it can be tree-shaken, reused (e.g. @vue/reactivity standalone), or retargeted (custom renderers, SSR, the test renderer).


2. Repository Architecture

2.1 Monorepo layout

core/
├── packages/                    Published packages
│   ├── reactivity/              @vue/reactivity   — standalone reactivity system
│   ├── shared/                  @vue/shared       — internal utilities (private)
│   ├── runtime-core/            @vue/runtime-core — renderer, component model (platform-agnostic)
│   ├── runtime-dom/             @vue/runtime-dom  — DOM-specific renderer + browser APIs
│   ├── runtime-test/            @vue/runtime-test — test renderer (private)
│   ├── compiler-core/           @vue/compiler-core— platform-agnostic template compiler
│   ├── compiler-dom/            @vue/compiler-dom — DOM-specific compiler transforms
│   ├── compiler-sfc/            @vue/compiler-sfc — single-file-component compiler
│   ├── compiler-ssr/            @vue/compiler-ssr — SSR codegen (private)
│   ├── server-renderer/         @vue/server-renderer — SSR runtime
│   ├── vue/                     vue              — the umbrella package (full + runtime builds)
│   └── vue-compat/              @vue/compat      — Vue 2 migration build
├── packages-private/            Non-published tooling & tests
│   ├── sfc-playground/          The online SFC playground (Vite app)
│   ├── template-explorer/       Compiler output explorer (Monaco)
│   ├── dts-test/                Type-level tests (tsc-checked)
│   ├── dts-built-test/          Tests against rolled-up .d.ts
│   └── vite-debug/              Vite integration debug harness
├── scripts/                     Build/dev/release Node scripts
├── changelogs/                  Generated changelog history
├── rollup.config.js             Main build configuration
├── rollup.dts.config.js         .d.ts rollup configuration
├── tsconfig.json / .build.json  TypeScript configuration
├── vitest.config.ts             Test configuration (4 projects)
└── eslint.config.js             Lint rules (with codebase-specific bans)

2.2 Package dependency graph

The dependency direction is strictly one-way (lower layers never import higher layers):

                         shared  (leaf — depended on by everything)
                           ▲
        ┌──────────────────┼──────────────────────────┐
   reactivity         compiler-core                     │
        ▲                  ▲                            │
   runtime-core       compiler-dom                      │
        ▲                  ▲          ▲                 │
   runtime-dom        compiler-ssr   compiler-sfc ──────┤
        ▲                  ▲          ▲                 │
        └──────► vue ◄─────┴──────────┘                 │
                  ▲                                      │
            server-renderer ────────────────────────────┘
Package Depends on (workspace) Role
@vue/shared — Pure utility functions, shared constants, type helpers.
@vue/reactivity shared The reactivity engine (ref, reactive, effect, computed, watch).
@vue/runtime-core reactivity, shared Virtual DOM, component lifecycle, the platform-agnostic renderer (createRenderer).
@vue/runtime-dom runtime-core, reactivity, shared, csstype DOM node ops, attribute/prop patching, createApp, Transition, custom elements.
@vue/compiler-core shared, @babel/parser, estree-walker, source-map-js, entities Parse → transform → codegen for templates.
@vue/compiler-dom compiler-core, shared DOM-specific parser options and directive transforms.
@vue/compiler-ssr compiler-dom, shared Generates SSR render functions.
@vue/compiler-sfc compiler-core, compiler-dom, compiler-ssr, shared, @babel/parser, magic-string, postcss, estree-walker, source-map-js Compiles .vue files (template + script + style).
@vue/server-renderer compiler-ssr, shared, vue Renders apps to strings/streams.
vue compiler-dom, compiler-sfc, runtime-dom, server-renderer, shared Umbrella package; full + runtime-only builds.
@vue/vue-compat @babel/parser, entities, estree-walker, source-map-js, vue Vue 2 compatibility build.

Note

@vue/shared is private to the framework (it has no dependencies of its own and is never meant to be installed directly by users). It contains the small utilities (extend, isObject, hasChanged, NOOP, camelize, normalizeClass, patch/shape flags, etc.) reused across every layer to keep bundle size down — note the ESLint rule that bans object spread in favor of extend from this package.

2.3 The vue umbrella package and its entries

The vue package re-exports @vue/runtime-dom and adds the in-browser compiler. Its exports map publishes several subpaths:

Subpath Resolves to Purpose
vue dist/vue.runtime.esm-bundler.js (import) / index.js (require) Main entry (runtime-only by default).
vue/server-renderer @vue/server-renderer SSR functions.
vue/compiler-sfc @vue/compiler-sfc (browser variant available) SFC compiler, for tooling and the playground.
vue/jsx-runtime / vue/jsx-dev-runtime jsx-runtime/index.js Automatic JSX runtime (h-based).
vue/jsx jsx.d.ts JSX type definitions.

The umbrella's packages/vue/src/index.ts registers the runtime compiler via registerRuntimeCompiler(compileToFunction) — this is the mechanism that lets the full build compile string templates on the fly, while the runtime-only build omits it entirely.


3. Build System

3.1 Build formats

Each package declares its target formats in package.json's buildOptions.formats. The vue package builds all seven:

Format Output suffix Module type Notes
esm-bundler .esm-bundler.js ES For bundlers; leaves __DEV__ etc. as flags for the bundler to define.
esm-bundler-runtime .runtime.esm-bundler.js ES Runtime-only bundler build (the default vue entry).
esm-browser .esm-browser.js ES Self-contained for native <script type=module>.
esm-browser-runtime .runtime.esm-browser.js ES Runtime-only native ESM.
cjs .cjs.js / .cjs.prod.js CommonJS Node (SSR, tests). Targets ES2019.
global .global.js / .global.prod.js IIFE Exposes window.Vue.
global-runtime .runtime.global.js IIFE Runtime-only global.

3.2 rollup.config.js internals

rollup.config.js is the single source of build truth. Key behaviors:

  • Target selection. It requires the TARGET environment variable (the package name) and throws TARGET package must be specified via --environment flag. if missing. scripts/build.js sets it per-package.
  • Compile-time defines (resolveDefine). Every build inlines a map of constants via esbuild's define (and the @rollup/plugin-replace plugin where esbuild's literal-only rules fall short). These constants drive dead-code elimination.
  • Enum inlining. scripts/inline-enums.js rewrites const enum-style values to literals at build time (the project bans const enum in source — see Coding Standards — and inlines plain enums instead).
  • Externalization (resolveExternal). For Node/bundler builds, all direct deps and peer deps are externalized; for browser/global builds, deps are inlined (tree-shaken deps like source-map-js, @babel/parser, estree-walker, entities/decode are only listed to suppress warnings).
  • Minification. Production browser/global builds run through an SWC-based renderChunk minify pass (compress.ecma: 2016, mangle: true, Safari 10 workaround), re-prepending the license banner.
  • Tree-shaking. treeshake.moduleSideEffects: false lets bundlers drop unused exports; circular-dependency warnings are suppressed (they're expected and benign in the runtime).

3.3 Compile-time feature flags

These constants are replaced at build time. They are the closest thing Vue has to a "configuration reference" — they shape what code ends up in each bundle.

Constant Meaning
__DEV__ Development build (enables warnings, dev-only checks). In bundler ESM builds it becomes !!(process.env.NODE_ENV !== 'production').
__TEST__ True only during Vue's own tests.
__BROWSER__ Build targets the browser.
__GLOBAL__ IIFE/global build.
__ESM_BUNDLER__ / __ESM_BROWSER__ ESM bundler / browser build.
__CJS__ CommonJS build (Node).
__SSR__ Build includes SSR branches (all non-global builds).
__COMPAT__ Vue 2 compat build.
__VERSION__ / __COMMIT__ Inlined version and commit.
__FEATURE_SUSPENSE__ Always true — <Suspense> support.
__FEATURE_OPTIONS_API__ __VUE_OPTIONS_API__ in bundler builds (user-tunable); true otherwise.
__FEATURE_PROD_DEVTOOLS__ __VUE_PROD_DEVTOOLS__ in bundler builds; false otherwise.
__FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__ __VUE_PROD_HYDRATION_MISMATCH_DETAILS__ in bundler builds; false otherwise.

Important

The three __VUE_* flags are the only ones intended for downstream consumers to define in their bundler. The rest are resolved entirely within Vue's own build. If you ship a library that bundles Vue, define __VUE_OPTIONS_API__, __VUE_PROD_DEVTOOLS__, and __VUE_PROD_HYDRATION_MISMATCH_DETAILS__ to avoid "feature flag not defined" warnings.

3.4 Type declaration build

build-dts runs tsc -p tsconfig.build.json --noCheck to emit raw .d.ts into temp/, then rollup.dts.config.js rolls each package's declarations into a single dist/{pkg}.d.ts using rollup-plugin-dts. A custom patchTypes plugin (AST-driven, via @babel/parser + magic-string) converts re-exported types to inline exports (so VitePress/defineComponent inference works) and appends per-package type augmentations (JSX, macros). For the vue package, a copyMts plugin duplicates vue.d.ts to vue.d.mts so Node ESM and CJS both get correct types.


4. Development & Operations

4.1 npm scripts (the operational CLI surface)

The root package.json scripts are how everything is built, tested, and released:

Script Command Purpose
dev node scripts/dev.js Watch-build a single package for development.
build node scripts/build.js Production build of all (or selected) packages.
build-dts tsc … && rollup -c rollup.dts.config.js Build rolled-up type declarations.
clean rimraf … Remove dist/, temp/, eslint cache.
check tsc --incremental --noEmit Full type check.
lint eslint --cache . Lint the codebase.
format / format-check prettier --write/--check Code formatting.
test vitest Run all tests (watch by default).
test-unit vitest --project unit* Unit tests only.
test-e2e build global + vitest --project e2e Puppeteer end-to-end tests.
test-dts run-s build-dts test-dts-only Type-level tests against built .d.ts.
test-coverage vitest run --project unit* --coverage Coverage report (v8 provider).
size run-s size-* && node scripts/usage-size.js Measure bundle sizes.
bench / bench-compare vitest bench … Reactivity/runtime benchmarks.
release node scripts/release.js Cut a release.
changelog conventional-changelog -p angular … Generate the changelog.
dev-sfc run-s dev-sfc-prepare dev-sfc-run Run the SFC playground against local source.

Tip

pnpm dev <package> (e.g. pnpm dev reactivity) rebuilds one package on change — the fastest loop when working on a single layer. pnpm dev-sfc spins up the playground wired to your local build, which is the best way to exercise the full compile→render path interactively.

4.2 Git hooks and commit conventions

simple-git-hooks (installed via postinstall) wires:

  • pre-commit: pnpm lint-staged && pnpm check — lints staged files (ESLint + Prettier) and runs a full type check.
  • commit-msg: node scripts/verify-commit.js — enforces Conventional Commits.

lint-staged runs Prettier on *.{js,json} and ESLint --fix + Prettier on *.ts(x).

Caution

The pre-commit hook runs a full tsc --noEmit, which can take significant time on a cold cache. Do not bypass it with --no-verify unless you have separately verified types — a type regression that lands on main breaks every downstream consumer's build.

4.3 Testing architecture

vitest.config.ts defines four test projects:

Project Environment Scope
unit node Most packages; excludes DOM-coupled packages and e2e.
unit-gc node (--expose-gc, forks pool) server-renderer's ssrWatch GC test.
unit-jsdom jsdom vue, vue-compat, runtime-dom tests that need a DOM.
e2e jsdom packages/vue/__tests__/e2e/* (Puppeteer-driven).

The config also defines the same compile-time flags as the build (with __DEV__: true, __TEST__: true, __FEATURE_* enabled) and aliases workspace packages via scripts/aliases.js so tests run against source, not built output. Coverage uses the v8 provider over packages/*/src/**, excluding entries that are not meaningfully unit-testable (e.g. profiling.ts, featureFlags.ts, hydrationStrategies.ts, Transition*).

Note

Type-level correctness is tested separately from runtime behavior: packages-private/dts-test contains .test-d.ts(x) files checked by tsc, and dts-built-test verifies the rolled-up declarations. A change that compiles but breaks public types is caught here, not by Vitest.


5. Reactivity Internals

The reactivity system was substantially rewritten for Vue 3.5 to use a doubly-linked-list dependency graph with version counters, replacing the older Set-based dependency collection. This is the most performance-critical subsystem in the framework.

5.1 Core data structures (packages/reactivity/src/dep.ts, effect.ts)

Type Role
Dep A dependency: one reactive property (or a computed/ref). Holds a version counter and a doubly-linked list of subscriber Links (subs).
Subscriber Anything that consumes reactive state: a ReactiveEffect or a ComputedRefImpl. Holds a doubly-linked list of its dependencies (deps/depsTail) and a bitmask of flags.
Link A node connecting one Dep to one Subscriber. Because the relationship is many-to-many, each link participates in two doubly-linked lists: the sub's dep-list (nextDep/prevDep) and the dep's sub-list (nextSub/prevSub). Each link carries a version.
targetMap A WeakMap<object, Map<key, Dep>> storing the { target → key → Dep } graph for reactive objects.
   reactive object property              effect / computed
        (a Dep)                           (a Subscriber)
          │                                     │
          ├── subs ──► Link ◄── deps ───────────┤
          │            │  ▲                      │
          │         nextSub nextDep              │
          ▼            ▼  │                      ▼
        (more subs)   Link (more deps)

5.2 Tracking and triggering

  • track(target, type, key) (called from proxy getters) finds (or lazily creates) the Dep for target[key] in targetMap, then calls dep.track(). If an effect is active (activeSub) and shouldTrack is on, it creates or reuses a Link between the dep and the active subscriber, appending it to the sub's dep-list tail.
  • trigger(target, type, key, …) finds affected deps and calls dep.trigger(), which bumps dep.version and the module-global globalVersion, then notifies subscribers. Array length changes, ADD/DELETE/CLEAR operations, and Map/Set iteration keys (ITERATE_KEY, MAP_KEY_ITERATE_KEY, ARRAY_ITERATE_KEY) are handled with special cases so iteration-dependent effects re-run correctly.

5.3 The globalVersion fast path

Every reactive mutation increments globalVersion. A ComputedRefImpl records the globalVersion at its last evaluation. When a computed is read, if globalVersion hasn't changed since, it can skip dependency-checking entirely — no reactive state changed anywhere, so the cache is definitely valid. This is a cheap global short-circuit before the finer-grained per-dep version check.

5.4 Batching (effect.ts)

Notifications are batched. startBatch()/endBatch() bracket a trigger; subscribers are collected into batchedSub/batchedComputed linked lists (marked with the NOTIFIED flag) and flushed at the end of the batch — effects run in original order, computeds are processed separately. Mutating methods that change array length (push, pop, splice, etc.) wrap their work in pauseTracking() + startBatch() to avoid the infamous length-tracking infinite loop (issue #2137).

5.5 Effect flags

ReactiveEffect and ComputedRefImpl carry a bitmask (EffectFlags) instead of multiple booleans, for compactness and speed:

Flag Meaning
ACTIVE The effect has not been stopped.
RUNNING Currently executing (used to detect/guard recursion).
TRACKING Should record dependencies while running.
NOTIFIED Already queued in the current batch.
DIRTY Needs re-evaluation (a dep changed).
ALLOW_RECURSE May re-trigger itself.
PAUSED Paused via .pause() — triggers are deferred.
EVALUATED (computed) Has been evaluated at least once.

5.6 Proxy handlers

  • baseHandlers.ts — BaseReactiveHandler (get), MutableReactiveHandler (get/set/deleteProperty/has/ownKeys), and ReadonlyReactiveHandler (blocks writes, warns in dev). The getter handles ref-unwrapping, the __v_* reactive flags (IS_REACTIVE, IS_READONLY, IS_SHALLOW, RAW, SKIP), array instrumentation, and lazy nested proxying. Four singleton handlers are exported: mutableHandlers, readonlyHandlers, shallowReactiveHandlers, shallowReadonlyHandlers.
  • collectionHandlers.ts — Special handling for Map/Set/WeakMap/WeakSet, whose methods (get/set/add/delete/has/forEach/iterators) must be instrumented rather than proxied via property access. Identity-key consistency is checked in dev (the "raw and reactive versions of the same object" warning).
  • arrayInstrumentations.ts — Reactive-aware versions of array methods. Iteration methods (map, filter, forEach, find, includes, indexOf, etc.) take an ARRAY_ITERATE dependency and wrap returned items in reactive proxies as needed. Identity-sensitive searches (includes/indexOf/lastIndexOf) retry with raw values so you can search by either the reactive or raw form.

5.7 Public surface vs. internal

packages/reactivity/src/index.ts exports the public API (ref, reactive, computed, watch, effect, effectScope, the type set, and the TrackOpTypes/TriggerOpTypes/ReactiveFlags enums). The Dep, Link, Subscriber, targetMap, globalVersion, and batching internals are not part of the public contract — runtime-core augments RefUnwrapBailTypes via declaration merging to teach ref-unwrapping about VNodes and component instances without creating a runtime dependency cycle.


6. Compiler & Runtime Pipeline

6.1 Compiler stages

The template compiler is a classic three-stage pipeline, split across compiler-core (platform-agnostic) and compiler-dom (browser specifics):

template string
   │  baseParse()            ── parser.ts → AST (RootNode)
   ▼
   AST
   │  transform()            ── transform.ts: node + directive transforms
   │    nodeTransforms:      transformElement, transformExpression, vIf, vFor,
   │                         vSlot, vOnce, vMemo, cacheStatic (static hoisting)…
   │    directiveTransforms:  vBind, vOn, vModel, vShow, vHtml, vText…
   ▼
   transformed AST (with codegenNode)
   │  generate()             ── codegen.ts → render function source + sourcemap
   ▼
   { code, ast, map }
  • compiler-core exposes baseCompile, baseParse, transform, generate, plus every individual transform and the ErrorCodes/createCompilerError machinery. It is target-agnostic.
  • compiler-dom supplies parserOptions (HTML namespaces, native tags), DOM directive transforms (v-html→transformVHtml, v-text, v-model override, v-on override, v-show, <Transition>), and stringifyStatic (turns large static subtrees into a single innerHTML string for performance). Its compile() composes these into baseCompile.
  • compiler-ssr reuses the DOM parser/transforms but swaps in SSR-specific transforms (ssrTransformElement, ssrTransformComponent, ssrVIf, ssrVFor, ssrVModel, ssrVShow, CSS-var injection) and emits SSR render functions via ssrCodegenTransform.

6.2 SFC compilation (compiler-sfc)

@vue/compiler-sfc is the bridge that build tools (@vitejs/plugin-vue, vue-loader) call. Its public API:

Function Purpose
parse(source) Split a .vue file into <template>, <script>, <script setup>, and <style> descriptor blocks (cached via parseCache).
compileTemplate(options) Compile the template block to a render function.
compileScript(descriptor, options) Process <script setup>, resolve the macros (defineProps/defineEmits/defineModel/…), and merge with <script>.
compileStyle / compileStyleAsync Scoped CSS, CSS Modules, and v-bind() in CSS via PostCSS.
rewriteDefault / rewriteDefaultAST Rewrite a module's default export for composition.
resolveTypeElements / inferRuntimeType Type-only prop/emit resolution (turns TS types into runtime declarations).

It bundles a forked @vue/consolidate for alternative template engines and exposes babelParse, MagicString, and walk for tooling.

Note

shouldTransformRef and the old reactivity-transform are gone — compiler-sfc keeps shouldTransformRef = () => false only to avoid breaking vite-plugin-vue < 5.0 that passed reactivityTransform: true. Do not build new features on reactivity transform.

6.3 Runtime rendering (runtime-core → runtime-dom)

runtime-core is platform-agnostic. createRenderer(options) takes a set of node operations (create/insert/remove/patchProp/…) and returns a { render, createApp } pair. This is how Vue supports multiple targets:

Renderer Node ops source Target
runtime-dom nodeOps + patchProp (packages/runtime-dom/src) Real browser DOM.
runtime-test nodeOps + patchProp (packages/runtime-test/src) An in-memory tree for assertions (serializeInner, triggerEvent).
Your custom renderer your own ops Canvas, native, terminal, etc.

runtime-dom lazily instantiates the renderer (ensureRenderer) so apps that only use the reactivity APIs don't pull in renderer code. createApp wraps the core app to add DOM container normalization, in-DOM template handling (full build), and dev-only checks (isNativeTag, deprecated-isCustomElement/compilerOptions guards). createSSRApp uses the hydration renderer (createHydrationRenderer) to adopt server markup instead of creating new nodes.

6.4 Hydration strategies (lazy hydration)

runtime-core exports hydrateOnIdle, hydrateOnVisible, hydrateOnMediaQuery, and hydrateOnInteraction — strategy factories for deferring hydration of async components until the browser is idle, the element is visible, a media query matches, or the user interacts. These power "islands"-style performance patterns.


7. Coding Standards & Conventions

eslint.config.js enforces several codebase-specific rules that contributors must respect:

Rule Rationale
No const enum The project inlines plain enums at build time; const enum breaks isolated modules. Use a regular enum.
No object rest in destructuring ({ ...rest } patterns) Output target is ES2016; rest/spread produces verbose helpers.
No object spread in expressions ({ ...obj }) esbuild transpiles it to verbose inline helpers — use extend() from @vue/shared.
No async/await syntax ES2016 target; avoid the generated state machine. Use promises/.then or the compiler's async helpers.
No optional chaining (?.) ES2016 target; it transpiles to verbose helpers.
No raw Node.js modules (except node:-prefixed, and inside compiler-sfc) Most of the codebase must be environment-agnostic.
No DOM globals (window, document) in env-agnostic packages Enforced per-package: DOM packages may use DOM globals, Node packages may use Node globals, shared may use neither restriction.
import type required for type-only imports Keeps the runtime graph clean and tree-shakeable.
Prefer @ts-expect-error over @ts-ignore Surfaces stale suppressions.

Important

These bans exist because Vue's source is shipped to users essentially as-authored (after esbuild transpilation to ES2016). Convenience syntax that looks free in app code (spread, async/await, ?.) expands into helper functions that bloat the framework's own bundle. When in doubt, mirror the surrounding code and reach for @vue/shared helpers.


8. Security Analysis

Vue is a client/SSR library, so its security surface is about safe rendering, not network/auth.

Area Behavior Guidance
HTML injection v-html and the innerHTML-based stringifyStatic optimization set raw HTML. Text interpolation ({{ }} / toDisplayString) is always escaped. Never bind untrusted content to v-html. The compiler even refuses v-html with children and warns on v-text misuse.
In-DOM templates The full build can compile a container's innerHTML as a template. The source explicitly marks these paths __UNSAFE__. Only mount over trusted in-DOM templates; never let user-controlled markup become a template. SSR output used as a template must not contain user data.
SSR escaping @vue/shared's escapeHtml is used throughout the server renderer for interpolated content and attributes. Trust the renderer's escaping for interpolations; be careful with v-html and any manually injected SSRContext data.
XSS via attributes runtime-dom's patchProp handles attribute vs. property assignment and supports Trusted Types (@types/trusted-types). In strict-CSP/Trusted-Types environments, configure a policy; Vue is Trusted-Types-aware.
Prototype pollution Reactive proxy handlers explicitly skip __proto__ and non-trackable keys (isNonTrackableKeys). Don't rely on inherited/proto keys being reactive.
Dependency surface Runtime deps are minimal and well-known (@babel/parser, magic-string, postcss, source-map-js, estree-walker, entities, csstype); most are compiler/build-time. Keep these patched; they affect build tooling more than runtime.

Caution

The single most common Vue security mistake is v-html with user content. Treat every v-html, innerHTML-equivalent render path, and selector-template mount (#id) as a potential XSS vector and audit accordingly.


9. Quality, Tech Debt & Improvement Areas

These are observations grounded in the current source and the community issue tracker; they are candidate areas for contributors.

  • Vapor mode is in flight. The issue tracker shows active [Vapor] / [runtime-vapor] work (e.g. #14844, #14787, #14851) — a compilation strategy that skips the virtual DOM. It is not yet a stable public API; expect churn in compiler and runtime internals around it.
  • Reactivity edge cases. reactive silently no-ops on non-extensible objects (#14893) — arguably should warn. watch with immediate: true and a static source running only once (#14898) is a recurring source of confusion; documentation/DX could be improved.
  • Type-level scaling. Very large prop union types can trip TS2590 ("union type too complex," #10514). Components with hundreds of literal-union prop values need workarounds.
  • Transition/animation gaps. <Transition> doesn't animate visibility (#2531); v-show enter animations differ from v-if/v-for in <TransitionGroup> (#14894).
  • SSR hydration robustness. Recent fixes around Teleport + Suspense unmount (#14876) and redundant mismatch logging (#14855) indicate the Teleport/Suspense/hydration intersection is a complex, regression-prone area worth additional test coverage.
  • Compiler crash hardening. Edge-case template inputs (<template v-for> + non-identifier :key + v-memo, #14859) have produced compiler crashes; fuzz-style template tests would help.

Note

Because Vue has no staging environment between main and published releases, the test matrix (unit + jsdom + e2e + dts) is the safety net. Any internals change to reactivity, the renderer, or the compiler should land with tests at the seam it touches.


10. Quick Reference

Package → npm name

Folder npm package Published?
packages/vue vue ✅
packages/reactivity @vue/reactivity ✅
packages/runtime-core @vue/runtime-core ✅
packages/runtime-dom @vue/runtime-dom ✅
packages/compiler-core @vue/compiler-core ✅
packages/compiler-dom @vue/compiler-dom ✅
packages/compiler-sfc @vue/compiler-sfc ✅
packages/server-renderer @vue/server-renderer ✅
packages/vue-compat @vue/compat ✅
packages/shared @vue/shared ✅ (internal)
packages/compiler-ssr @vue/compiler-ssr internal
packages/runtime-test @vue/runtime-test internal

Common contributor commands

pnpm install                 # bootstrap (pnpm enforced)
pnpm dev reactivity          # watch-build one package
pnpm dev-sfc                 # run the SFC playground on local source
pnpm test-unit               # unit tests
pnpm test --project unit-jsdom   # DOM tests
pnpm check                   # full type check
pnpm lint                    # eslint
pnpm build vue               # production build of the vue package
pnpm build-dts               # build rolled-up type declarations
pnpm size                    # measure bundle sizes

Key source files for orientation

File What it anchors
packages/vue/src/index.ts Full build entry; registers the runtime compiler.
packages/runtime-dom/src/index.ts createApp/createSSRApp, DOM renderer bootstrap.
packages/runtime-core/src/index.ts The entire runtime public API surface.
packages/reactivity/src/{dep,effect,computed,ref,reactive}.ts The reactivity engine.
packages/compiler-core/src/{parser,transform,codegen}.ts The compiler pipeline.
rollup.config.js Build formats, feature flags, externalization.
vitest.config.ts Test projects and aliases.