6.processComponent 组件处理
通过 n1 是否存在判断挂载/更新阶段
const processComponent = (
n1: VNode | null, // 旧虚拟节点
n2: VNode, // 新虚拟节点
container: RendererElement,
anchor: RendererNode | null,
parentComponent: ComponentInternalInstance | null,
parentSuspense: SuspenseBoundary | null,
namespace: ElementNamespace,
slotScopeIds: string[] | null,
optimized: boolean,
) => {
n2.slotScopeIds = slotScopeIds // 设置作用域插槽ID
if (n1 == null) { // 初次挂载
if (n2.shapeFlag & ShapeFlags.COMPONENT_KEPT_ALIVE) { // KeepAlive组件激活逻辑
;(parentComponent!.ctx as KeepAliveContext).activate(
n2,
container,
anchor,
namespace,
optimized,
)
} else { // 普通组件挂载
mountComponent(
n2,
container,
anchor,
parentComponent,
parentSuspense,
namespace,
optimized,
)
}
} else { // 组件更新
updateComponent(n1, n2, optimized)
}
}
1.mountComponent 组件挂载
这是vue组件挂载的入口函数
函数接收多个参数,包括初始VNode、容器、锚点、父组件等,然后,创建组件实例的部分,使用了createComponentInstance函数,并将实例赋值给initialVNode.component
处理props和slots的部分,调用了setupComponent,这是Vue 3组合式API的核心,负责初始化组件的props、slots以及执行setup函数
const mountComponent: MountComponentFn = (
initialVNode, // 初始虚拟节点
container, // 挂载容器
anchor, // 锚点位置
parentComponent, // 父组件实例
parentSuspense, // 父级Suspense边界
namespace: ElementNamespace, // 命名空间(svg/mathml)
optimized // 是否启用优化模式
) => {
// 1. 兼容Vue2处理
const compatMountInstance =
__COMPAT__ && initialVNode.isCompatRoot && initialVNode.component
// 2. 创建组件实例
const instance: ComponentInternalInstance =
compatMountInstance ||
(initialVNode.component = createComponentInstance(
initialVNode,
parentComponent,
parentSuspense,
))
// 3. HMR注册(开发模式)
if (__DEV__ && instance.type.__hmrId) {
registerHMR(instance) // 热更新注册
}
// 4. 开发模式性能追踪
if (__DEV__) {
pushWarningContext(initialVNode) // 错误上下文
startMeasure(instance, `mount`) // 性能监控开始
}
// 5. KeepAlive特殊处理
if (isKeepAlive(initialVNode)) {
;(instance.ctx as KeepAliveContext).renderer = internals // 注入渲染器
}
// 6. 初始化组件状态
if (!(__COMPAT__ && compatMountInstance)) {
setupComponent(instance) // 核心初始化逻辑:
// - 解析props
// - 初始化slots
// - 执行setup()
}
// 7. 异步组件处理
if (__FEATURE_SUSPENSE__ && instance.asyncDep) {
parentSuspense?.registerDep(instance, setupRenderEffect) // 注册到Suspense
// 创建占位注释节点
if (!initialVNode.el) {
const placeholder = (instance.subTree = createVNode(Comment))
processCommentNode(null, placeholder, container!, anchor)
}
} else {
// 8. 同步渲染执行
setupRenderEffect(
instance,
initialVNode,
container,
anchor,
parentSuspense,
namespace,
optimized,
)
}
// 9. 开发模式清理
if (__DEV__) {
popWarningContext() // 弹出错误上下文
endMeasure(instance, `mount`) // 性能监控结束
}
}
组件实例生命周期
graph TD
A[创建实例] --> B[HMR注册]
B --> C[KeepAlive处理]
C --> D[初始化props/slots]
D --> E{异步组件?}
E -->|是| F[注册Suspense]
E -->|否| G[同步渲染]
F --> H[创建占位节点]
1.创建组件实例
组件实例的含义如下
export function createComponentInstance(
vnode: VNode, // 组件对应的虚拟节点
parent: ComponentInternalInstance | null, // 父组件实例
suspense: SuspenseBoundary | null, // Suspense边界状态
) {
// 核心逻辑分4个阶段:
// 1. 确定组件类型和应用上下文
const type = vnode.type as ConcreteComponent
const appContext = (parent ? parent.appContext : vnode.appContext) || emptyAppContext
// 2. 创建组件实例对象
// 核心属性矩阵
const instance: ComponentInternalInstance = {
// 基础标识类属性
uid: uid++, // 组件唯一递增ID (每次创建+1)
vnode, // 关联的虚拟节点对象
type, // 组件类型(选项式/函数式组件)
parent, // 父组件实例引用
// 应用上下文相关
appContext, // 应用全局配置(包含全局组件/指令等)
root: null!, // 组件树根实例(初始化后立即设置)
// 渲染相关
subTree: null!, // 当前组件渲染的虚拟DOM树
effect: null!, // 响应式effect实例
update: null!, // 组件更新函数(由scheduler调度)
// 响应式系统
scope: new EffectScope(/*detached*/true), // 独立的响应式作用域
provides: parent ? parent.provides : ..., // 依赖注入容器(原型链继承父级)
// 性能优化
accessCache: null!, // 代理属性访问缓存(减少hasOwnProperty调用)
renderCache: [], // 渲染函数结果缓存(优化重复渲染)
// 组件配置
propsOptions: normalizePropsOptions(...), // 标准化后的props配置
emitsOptions: normalizeEmitsOptions(...), // 标准化后的emits配置
inheritAttrs: type.inheritAttrs, // 是否继承原生属性
// 状态管理
ctx: EMPTY_OBJ, // 模板执行上下文(开发环境增强)
setupState: EMPTY_OBJ, // setup()返回的状态对象
setupContext: null, // setup上下文(attrs/slots/emit)
// 异步处理
suspense, // 所属Suspense边界
asyncDep: null, // 异步依赖(用于Suspense)
asyncResolved: false, // 异步加载完成标记
// 生命周期状态
isMounted: false, // 是否已挂载
isUnmounted: false, // 是否已卸载
isDeactivated: false, // 是否被keep-alive停用
// 生命周期钩子缩写(数组存储多个钩子):
bc: null, // beforeCreate
c: null, // created
bm: null, // beforeMount
m: null, // mounted
// ...其他钩子类似
}
// 3. 开发模式特殊处理
if (__DEV__) {
instance.ctx = createDevRenderContext(instance) // 调试用上下文
}
// 4. 建立组件树关系
instance.root = parent ? parent.root : instance // 设置根实例
instance.emit = emit.bind(null, instance) // 绑定emit方法
}
2.setupComponent
setupComponent函数接收一个组件实例instance和一个标志isSSR,用于判断是否是服务端渲染。函数内部处理了props、slots,并根据是否是状态式组件调用不同的逻辑
graph TD
A[开始] --> B[初始化Props]
B --> C[初始化Slots]
C --> D{状态式组件?}
D -->|是| E[初始化状态式组件]
D -->|否| F[结束]
export function setupComponent(
instance: ComponentInternalInstance,
isSSR = false,
) {
isSSR && setInSSRSetupState(isSSR) // 设置SSR状态
const { props, children } = instance.vnode // 从虚拟节点解构属性
const isStateful = isStatefulComponent(instance) // 判断是否状态式组件
initProps(instance, props, isStateful, isSSR) // 标准化props配置,建立响应式绑定
initSlots(instance, children) // 初始化slots
const setupResult = isStateful
? setupStatefulComponent(instance, isSSR) // 执行setup函数,创建代理对象
: undefined // 函数式组件直接返回undefined
isSSR && setInSSRSetupState(false) // 重置SSR状态
return setupResult
}
有状态组件和无状态组件
有状态组件:能维护和自身状态的组件,一般包含props、state,有自己的生命周期
无状态组件:纯函数组件,主要负责接收props绘制ui,没有任何副作用
3.初始化有状态组件 setupStatefulComponent
setupStatefulComponent是Vue 3中处理状态式组件的核心函数,负责执行setup函数并设置组件的响应式代理
核心代理创建PublicInstanceProxyHandlers,使用Proxy实现模板中 this 的代理访问
instance.proxy = new Proxy(instance.ctx, PublicInstanceProxyHandlers)
graph TD
A[开始] --> B{开发模式?}
B -->|是| C[验证组件名]
C --> D[验证子组件]
D --> E[验证指令]
E --> F[检查编译器选项]
B -->|否| G[跳过验证]
function setupStatefulComponent(
instance: ComponentInternalInstance,
isSSR: boolean,
) {
const Component = instance.type as ComponentOptions
// 开发环境验证(组件名/子组件/指令/编译器选项)
if (__DEV__) {
validateComponentName(Component.name, ...) // 组件命名规范检查
validateChildComponents(Component.components) // 子组件合法性检查
validateDirectives(Component.directives) // 指令命名规范检查
checkCompilerOptions(Component.compilerOptions) // 编译器选项兼容性检查
}
// 1. 创建代理访问缓存
instance.accessCache = Object.create(null)
// 2. 创建公共实例代理(响应式系统核心)
instance.proxy = new Proxy(instance.ctx, PublicInstanceProxyHandlers)
// 3. 执行setup函数
const { setup } = Component
if (setup) {
// 创建setup上下文(包含attrs/slots/emit/expose)
const setupContext = createSetupContext(instance)
// 执行setup前的准备工作
const reset = setCurrentInstance(instance) // 设置当前实例
pauseTracking() // 暂停响应式追踪
// 调用setup函数(带错误处理)实际就是trycath调用handleError
const setupResult = callWithErrorHandling(
setup,
[shallowReadonly(instance.props), setupContext]
)
// 执行后清理
resetTracking() // 恢复响应式追踪
reset() // 重置当前实例
// 处理setup结果
if (isPromise(setupResult)) { // 异步setup处理
return setupResult
.then((resolvedResult: unknown) => {
handleSetupResult(instance, resolvedResult, isSSR)
})
.catch(e => {
handleError(e, instance, ErrorCodes.SETUP_FUNCTION)
})
} else { // 同步setup处理
handleSetupResult(instance, setupResult, isSSR)
}
} else { // 无setup函数的情况(选项式组件)
finishComponentSetup(instance, isSSR)
}
}
核心代理处理器 PublicInstanceProxyHandlers
PublicInstanceProxyHandlers是Vue组件实例代理的核心,负责管理属性的访问和修改,确保响应式系统的正确运作,同时通过缓存和优化提升性能
export const PublicInstanceProxyHandlers: ProxyHandler<any> = {
get({ _: instance }, key: string) {
// 核心访问逻辑分4个阶段:
// 1. 特殊标记处理(SKIP/__isVue)
// 2. 非$开头属性访问(setup/data/props/ctx)
// 3. 公共属性访问($attrs/$slots等)
// 4. 全局属性和CSS模块处理
// 性能优化关键点:
const { accessCache } = instance
if (key[0] !== '$') {
const n = accessCache![key]
if (n !== undefined) { // 缓存命中直接返回
switch(n) { /*...*/ }
}
// 缓存未命中时按顺序检查各数据源
}
},
set({ _: instance }, key, value) {
// 属性赋值安全策略:
// 1. setupState优先
// 2. data属性可写
// 3. props只读保护
// 4. $开头的公共属性只读
}
}
handleSetupResult 针对setup返回值类型作不同处理
区分处理如下:
| 返回值类型 | 处理方式 | 应用场景 | |
|---|---|---|
| 函数 | 设为渲染函数 | 动态模板/JSX |
| 普通对象 | 代理为响应式状态 | Composition API |
| VNode对象 | 开发环境警告 | 防止直接返回模板节点 |
| 其他类型 | 开发环境类型警告 | 强制类型约束 |
export function handleSetupResult(
instance: ComponentInternalInstance,
setupResult: unknown,
isSSR: boolean,
) {
// 核心处理逻辑分3种情况:
// 1. setup返回函数(作为渲染函数)
if (isFunction(setupResult)) {
// 服务端渲染特殊处理
if (__SSR__ && (instance.type as ComponentOptions).__ssrInlineRender) {
instance.ssrRender = setupResult // 设置SSR专用渲染函数
} else {
instance.render = setupResult as InternalRenderFunction // 设置客户端渲染函数
}
}
// 2. setup返回对象(状态对象)
else if (isObject(setupResult)) {
// 开发环境错误检查
if (__DEV__ && isVNode(setupResult)) {
warn('setup()不应直接返回VNode') // 提示应返回渲染函数
}
// 状态处理
// proxyRefs实现自动解包ref.value:
// 输入:{ count: ref(0) }
// 输出:模板中可直接使用count
instance.setupState = proxyRefs(setupResult)
if (__DEV__) {
exposeSetupStateOnRenderContext(instance) // 开发模式暴露setup状态
}
}
// 3. 非法返回值处理
else if (__DEV__ && setupResult !== undefined) {
warn(`setup()应返回对象,实际返回:${typeof setupResult}`) // 类型错误提示
}
// 最终处理
finishComponentSetup(instance, isSSR) // 完成组件设置
}
finishComponentSetup 完成组件设置
finishComponentSetup 函数是Vue组件初始化过程中的关键环节
主要负责:
-
检查并生成渲染函数,优先使用setup返回的render
-
处理选项式API的选项合并
applyOptions
export function finishComponentSetup(
instance: ComponentInternalInstance,
isSSR: boolean,
skipOptions?: boolean,
) {
//这里处理Vue 2.x的兼容逻辑, convertLegacyRenderFn 会将选项式API转换为兼容模式下的渲染函数
if (__COMPAT__) {
convertLegacyRenderFn(instance)
if (__DEV__ && Component.compatConfig) {
validateCompatConfig(Component.compatConfig)
}
}
//组件没有render函数时,会尝试通过模板编译生成render函数。编译过程会根据不同配置合并全局和组件的编译器选项
if (!instance.render) {
if (!isSSR && compile && !Component.render) {
// 模板编译逻辑
const template = /* 模板来源判断 */;
if (template) {
// 合并编译器选项
const finalCompilerOptions = extend(...);
// 执行编译
Component.render = compile(template, finalCompilerOptions);
}
}
// 设置实例的render函数
instance.render = (Component.render || NOOP) as InternalRenderFunction;
}
//当启用选项式API时(默认),会调用 applyOptions 处理组件选项(data、methods等)
if (__FEATURE_OPTIONS_API__ && !(__COMPAT__ && skipOptions)) {
applyOptions(instance)
}
}
选项式API处理函数 applyOptions
applyOptions函数接收一个组件实例,然后处理各种选项,比如data、computed、methods、watch等。这符合Vue 2.x选项式API的处理方式,因此这个函数的主要作用是将选项合并到组件实例中
-
首先函数解构了各种选项,包括data、computed、methods等
-
处理inject和methods的部分,
resolveInjections函数负责解析注入的依赖,而methods被绑定到组件实例的上下文中。这里使用了Object.defineProperty -
data选项的处理中,函数检查data是否是一个函数,并调用它获取数据对象,然后使用
reactive将其转换为响应式对象。这符合Vue 3的响应式系统设计。同时,开发环境下会对data中的每个属性进行检查,确保没有重复,并通过Object.defineProperty将它们暴露到上下文中 -
computed和watch的处理部分,computed属性通过
computed函数创建,并绑定到上下文,而watch选项则通过createWatcher创建观察者。provide选项的处理使用了provide函数。 -
生命周期钩子的注册部分,使用
registerLifecycleHook将选项中的钩子函数注册到对应的生命周期事件上。这里还处理了Vue 2.x的兼容性钩子,如beforeDestroy和destroyed,将它们映射到Vue 3的等效钩子上 -
最后,处理expose选项,将需要暴露的属性定义到实例的
exposed对象上,并设置组件的render函数和其他资源,如components和directives选项初始化顺序 :
graph TD
A[Props] --> B[Inject]
B --> C[Methods]
C --> D[Data]
D --> E[Computed]
E --> F[Watch]
export function applyOptions(instance: ComponentInternalInstance) {
// 核心处理流程:
// 1. 合并选项(包含mixins/extends)
const options = resolveMergedOptions(instance)
// 2. 开发环境属性重复检查
const checkDuplicateProperties = __DEV__ ? createDuplicateChecker() : null
// 3. 生命周期处理顺序
if (options.beforeCreate) {
callHook(options.beforeCreate, instance, LifecycleHooks.BEFORE_CREATE)
}
// 4. 解构各选项
const {
// state
data: dataOptions,
computed: computedOptions,
methods,
watch: watchOptions,
provide: provideOptions,
inject: injectOptions,
// lifecycle
created,
beforeMount,
mounted,
beforeUpdate,
updated,
activated,
deactivated,
beforeDestroy,
beforeUnmount,
destroyed,
unmounted,
render,
renderTracked,
renderTriggered,
errorCaptured,
serverPrefetch,
// public API
expose,
inheritAttrs,
// assets
components,
directives,
filters,
} = options
// 5.依赖注入检查
//- injectOptions :组件选项中的 inject 配置,支持数组或对象格式
//- ctx :组件实例的上下文对象,注入的属性会被挂载到这里
//- checkDuplicateProperties :开发环境下的属性重复检查器
if (injectOptions) {
resolveInjections(injectOptions, ctx, checkDuplicateProperties)
}
//6.组件选项中定义的methods绑定到组件实例的上下文(ctx)中
if (methods) {
for (const key in methods) {
const methodHandler = (methods as MethodOptions)[key]
if (isFunction(methodHandler)) {
//测试环境用Object.defineProperty暴露到上下文
if (__DEV__) {
Object.defineProperty(ctx, key, {
value: methodHandler.bind(publicThis),
configurable: true,
enumerable: true,
writable: true,
})
} else {
//线上直接赋值
ctx[key] = methodHandler.bind(publicThis)
}
if (__DEV__) {
checkDuplicateProperties!(OptionTypes.METHODS, key)
}
} else if (__DEV__) {
warn(
`Method "${key}" has type "${typeof methodHandler}" in the component definition. ` +
`Did you reference the function correctly?`,
)
}
}
}
// 7. 响应式数据初始化
if (dataOptions) {
instance.data = reactive(dataOptions.call(publicThis, publicThis))
}
// 8. computed函数创建
if (computedOptions) {
for (const key in computedOptions) {
const opt = (computedOptions as ComputedOptions)[key]
const get = isFunction(opt)
? opt.bind(publicThis, publicThis)
: isFunction(opt.get)
? opt.get.bind(publicThis, publicThis)
: NOOP
const set =
!isFunction(opt) && isFunction(opt.set)
? opt.set.bind(publicThis)
: __DEV__
? () => {
warn(
`Write operation failed: computed property "${key}" is readonly.`,
)
}
: NOOP
const c = computed({
get,
set,
})
Object.defineProperty(ctx, key, {
enumerable: true,
configurable: true,
get: () => c.value,
set: v => (c.value = v),
})
if (__DEV__) {
checkDuplicateProperties!(OptionTypes.COMPUTED, key)
}
}
}
//createWatcher 创建观察者
if (watchOptions) {
for (const key in watchOptions) {
createWatcher(watchOptions[key], ctx, publicThis, key)
}
}
//provide选项的处理使用了`provide`函数
if (provideOptions) {
const provides = isFunction(provideOptions)
? provideOptions.call(publicThis)
: provideOptions
Reflect.ownKeys(provides).forEach(key => {
provide(key, provides[key])
})
}
if (created) {
callHook(created, instance, LifecycleHooks.CREATED)
}
// 9. 生命周期钩子注册
registerLifecycleHooks(options, publicThis)
}
依赖注入处理流程
graph TD
A[检查inject选项] --> B{存在注入配置?}
B -->|是| C[解析注入来源]
B -->|否| D[跳过处理]
C --> E[处理数组/对象格式]
E --> F[从祖先组件查找provide]
F --> G[注入到组件上下文]
处理methods 流程图
graph TD
A[遍历methods选项] --> B{是函数类型?}
B -->|是| C[开发环境特殊处理]
B -->|否| D[生产环境直接绑定]
C --> E[使用defineProperty定义属性]
D --> F[直接赋值到上下文]
E --> G[设置可配置/可枚举/可写]
F --> H[绑定组件实例上下文]
处理data流程图
- 类型校验 :强制要求 data 必须是函数(开发环境下)
- 返回值校验 :返回值必须是普通对象(非Promise/非数组等)
- 异步校验 :禁止返回Promise(提示使用setup+Suspense)
- 使用 reactive() 创建深度响应式对象
- 响应式系统基于Proxy实现(Vue 3核心特性)
graph TD
A[检查data选项] --> B{存在配置?}
B -->|是| C[开发环境校验]
B -->|否| D[跳过处理]
C --> E[校验是否为函数]
E --> F[执行data函数]
F --> G[校验返回值类型]
G --> H[创建响应式对象]
H --> I[开发环境代理属性]
初始化组件结束后,进入渲染阶段