CodeVetter · Repo Unpack · Data flow
vuejs/core
Two largely independent pipelines meet at the component instance. Compile-time: template/SFC source string → tokenizer/parser → AST → transform passes (which mutate the AST and register runtime helpers) → codegen → render-function source. Runtime: props/slots enter via vnodes, reactive state is owned by `Dep` objects linked to `Subscriber`s, changes call `trigger()` which notifies effects, effects are batched into the scheduler queue, and the flush drives `patch()` which writes to the host platform through the injected `RendererOptions`. Output boundaries are exactly three: DOM mutations via `nodeOps`/`patchProp`, an SSR string/stream buffer, and generated JS source text.
- `baseCompile` is the single compile funnel: it resolves `prefixIdentifiers`, calls `baseParse(source, resolvedOptions)` when given a string, composes user `nodeTransforms`/`directiveTransforms` after the base preset, runs `transform(ast, ...)`, and returns `generate(ast, resolvedOptions)`.
- The base transform preset is order-sensitive and documented as such — transformVBindShorthand, transformOnce, transformIf, transformMemo, transformFor, then (non-browser only) trackVForSlotScopes + transformExpression, then transformSlotOutlet, transformElement, trackSlotScopes, transformText — with directive transforms keyed `on`/`bind`/`model`.
- compiler-dom layers platform behaviour on top by prepending `ignoreSideEffectTags`, adding `transformStyle` (+ dev-only `transformTransition` and `validateHtmlNesting`), overriding the core `model`/`on` directive transforms, and setting `transformHoist: stringifyStatic` for non-browser builds.
- compiler-ssr reuses the same `baseParse`/`transform`/`generate` primitives but forces `ssr: true`, `prefixIdentifiers: true`, `cacheHandlers: false`, `hoistStatic: false`, stores the raw options in a `rawOptionsMap` WeakMap keyed by AST root so slot sub-transforms can recover them, and swaps in ssr* node transforms.
- SFC parsing is memoised: `parse.ts` computes a source key and consults `parseCache`, an LRU of max 500 entries created by `createCache()` — which downgrades to a plain `Map` in `__GLOBAL__`/`__ESM_BROWSER__` builds where lru-cache is unavailable.
- `compileScript` merges `<script>` and `<script setup>` through a `ScriptCompileContext`, hard-errors if the two blocks declare different `lang`, returns non-JS/TS blocks untouched, and routes the no-setup case to `processNormalScript(ctx, scopeId)`.
- Type-only props/emits resolution reaches outside the SFC: `resolveFS` in resolveType.ts builds a filesystem host from `ctx.options.fs` or falls back to `ts.sys`, rewriting `.vue.ts` paths back to `.vue`, and walks tsconfig references to resolve imported types across files.
- Reactive reads flow through `track(target, type, key)` in dep.ts which links the active `Subscriber` to a `Dep`; writes flow through `trigger()` which bumps the module-global `globalVersion` counter used to short-circuit stale computed recomputation.
- `ReactiveEffect.run()` swaps in `activeSub`/`shouldTrack`, runs `cleanupEffect` + `prepareDeps` before the fn and `cleanupDeps` after, and dev-warns 'Active effect was not restored correctly' if `activeSub` drifted — the double-buffered dep-linking scheme that replaces Vue 3.4's Set-based deps.
- Component update jobs are id-ordered: `queueJob` fast-paths an append when the job id is ≥ the tail's id and otherwise binary-inserts via `findInsertionIndex`, ensuring parents flush before children; `queueFlush` schedules `flushJobs` on a resolved promise microtask.
- `flushJobs` iterates the queue with `callWithErrorHandling`, clears QUEUED flags in a `finally` block even after a throw, then calls `flushPostFlushCbs` and recurses if either queue refilled during the flush.
- All DOM writes funnel through the `rendererOptions` object = `extend({ patchProp }, nodeOps)` passed to `createRenderer`; inside the renderer they are reachable only as the `o` field of the `internals` object shared with Teleport, Suspense and KeepAlive.
- SSR output is a nested `SSRBuffer` of strings and promises; `renderToString` awaits `renderComponentVNode(vnode)` then `unrollBuffer`, which takes a fully synchronous path (`unrollBufferSync`) when `buffer.hasAsync` is false and otherwise resolves promises in place before concatenating.