深入解析 Vue 包:`vue` 究竟导出了什么?
本文系统梳理 Vue 3 各子包(
vue、@vue/reactivity、@vue/runtime-core、@vue/runtime-dom、@vue/compiler-core、@vue/compiler-dom、@vue/shared)的完整导出结构,重点覆盖官方文档未详细说明、日常开发中被忽视但架构价值极高的 API。
一、Vue 包体系全景:Monorepo 架构
很多开发者误认为 vue 是一个完整的实现包,实则它只是一个 Facade(门面模块) :
vue(聚合导出层)
│
├── @vue/runtime-dom ← 浏览器平台渲染层
│ └── @vue/runtime-core ← 平台无关运行时
│ └── @vue/reactivity ← 纯响应式系统
│
├── @vue/compiler-dom ← 浏览器模板编译器
│ └── @vue/compiler-core ← 平台无关编译器
│
└── @vue/shared ← 内部共享工具函数
每个子包都可以独立安装使用,这正是 Vue 3 架构解耦的核心体现。
二、@vue/reactivity:独立响应式引擎
这是 Vue 3 最具突破性的设计——响应式系统与框架完全解耦,可以在任何 JS 环境中独立使用。
npm install @vue/reactivity
2.1 核心响应式原语
ref / shallowRef / customRef
import { ref, shallowRef, customRef } from '@vue/reactivity'
// 标准 ref:深度响应
const state = ref({ a: { b: 1 } })
// shallowRef:只有 .value 本身是响应式,内部属性不追踪
const shallow = shallowRef({ count: 0 })
shallow.value.count++ // 不触发更新
shallow.value = { count: 1 } // 触发更新
// customRef:完全自定义追踪时机(防抖、节流场景极为有用)
function useDebouncedRef(value, delay = 200) {
let timer
return customRef((track, trigger) => ({
get() {
track() // 手动声明依赖追踪
return value
},
set(newValue) {
clearTimeout(timer)
timer = setTimeout(() => {
value = newValue
trigger() // 手动触发更新
}, delay)
}
}))
}
customRef 是实现防抖输入、异步数据源等场景的底层利器,但鲜少被人使用。
reactive / shallowReactive / readonly / shallowReadonly
import { reactive, shallowReactive, readonly, shallowReadonly } from '@vue/reactivity'
// shallowReactive:只追踪顶层属性,不深度转换
const state = shallowReactive({
user: { name: 'Tom' } // user.name 的变化不会触发更新
})
// readonly:深度只读代理,任何写入都会在 dev 环境报警告
const config = readonly({ api: 'https://example.com' })
// shallowReadonly:只有顶层只读,嵌套对象仍可修改
const mixed = shallowReadonly({ nested: { value: 1 } })
mixed.nested.value = 2 // 允许(不报警告)
mixed.nested = {} // 阻止(报警告)
2.2 副作用系统底层 API(极少被直接使用)
effect / ReactiveEffect
effect 是 Vue 响应式系统最底层的副作用原语,computed、watch 都是基于它构建的。
import { effect, reactive } from '@vue/reactivity'
const state = reactive({ count: 0 })
// effect 会立即执行,并自动追踪其中访问的响应式数据
const runner = effect(() => {
console.log('count is:', state.count)
})
state.count++ // 自动重新执行 effect
// 手动停止追踪
runner.effect.stop()
effectScope / getCurrentScope / onScopeDispose
这组 API 是 Vue 3.2 引入的副作用作用域管理机制,专为编写可复用组合函数设计,但日常业务代码中极少被直接使用。
import { effectScope, getCurrentScope, onScopeDispose } from '@vue/reactivity'
// 创建一个作用域,批量管理所有 effect/watch/computed
const scope = effectScope()
scope.run(() => {
const doubled = computed(() => count.value * 2)
watchEffect(() => console.log(doubled.value))
})
// 一次性停止作用域内所有副作用——无需逐一手动 stop()
scope.stop()
架构价值:在大型组合函数库(如 VueUse)中,effectScope 是正确管理副作用生命周期的标准方式,避免内存泄漏。
// 在自定义组合函数中使用
function useFeature() {
const scope = effectScope()
scope.run(() => {
// 所有 effect 在这里注册
onScopeDispose(() => {
// scope 被 stop 时的清理逻辑
scope.stop()
})
})
return scope
}
pauseTracking / resumeTracking / resetTracking
这组 API 允许手动控制依赖追踪的暂停与恢复,是构建高级响应式工具的基础。
import { pauseTracking, resetTracking, effect } from '@vue/reactivity'
effect(() => {
state.a // 正常追踪
pauseTracking()
state.b // 访问但不追踪,state.b 变化不会触发 re-run
resetTracking()
state.c // 恢复正常追踪
})
实际应用场景:在实现 readonly 包装、不希望某些读操作建立依赖时使用。
trackOpBit / triggerRef
import { ref, triggerRef } from '@vue/reactivity'
// triggerRef:强制触发 shallowRef 的更新(直接修改内部结构后手动通知)
const state = shallowRef({ list: [1, 2, 3] })
state.value.list.push(4) // 直接改内部,不触发更新
triggerRef(state) // 手动强制触发
2.3 工具函数
toRaw / markRaw
import { reactive, toRaw, markRaw } from '@vue/reactivity'
const state = reactive({ data: {} })
// toRaw:获取响应式对象的原始对象(绕过 Proxy),用于性能敏感操作
const raw = toRaw(state) // 直接操作,不触发任何追踪
// markRaw:标记对象永不被转为响应式(第三方库实例、大型数据集等)
const chart = markRaw(new ECharts())
const state2 = reactive({ chart }) // chart 不会被代理
架构意义:在将第三方库对象(如 Canvas 实例、WebSocket 对象)放入响应式状态时,必须用 markRaw 避免性能问题。
proxyRefs
import { proxyRefs, ref } from '@vue/reactivity'
// proxyRefs:自动解包对象中的所有 ref(这正是 setup() 返回值的内部处理机制)
const state = { count: ref(0), name: ref('Tom') }
const proxied = proxyRefs(state)
proxied.count // 直接访问,无需 .value(内部自动解包)
这是 Vue 模板自动解包 ref 的底层实现机制。
isRef / isReactive / isReadonly / isProxy / isShallow
import { ref, reactive, readonly, isRef, isReactive, isReadonly, isProxy, isShallow, shallowRef } from '@vue/reactivity'
isRef(ref(0)) // true
isReactive(reactive({})) // true
isReadonly(readonly({})) // true
isProxy(reactive({})) // true(reactive 和 readonly 都是 Proxy)
isShallow(shallowRef(0)) // true(Vue 3.2+ 新增)
unref
import { unref, ref } from '@vue/reactivity'
// unref:安全地获取 ref 的值,非 ref 原样返回
function useValue(val) {
return unref(val) // 不需要判断 isRef
}
useValue(ref(42)) // 42
useValue(42) // 42
这是编写接受 MaybeRef<T> 参数的组合函数的标准做法。
toRef / toRefs / toValue(Vue 3.3+)
import { reactive, toRef, toRefs, toValue } from '@vue/reactivity'
const state = reactive({ x: 1, y: 2 })
// toRef:从 reactive 对象中创建单个属性的 ref(保持响应式连接)
const xRef = toRef(state, 'x')
// toRefs:将整个 reactive 对象解构为 ref 集合(解构时保持响应性的核心工具)
const { x, y } = toRefs(state)
// toValue(3.3+):同 unref,但还能接受 getter 函数
const val = toValue(() => state.x + 1) // 执行 getter 并返回结果
2.4 计算属性底层
computed 的完整签名
import { computed } from '@vue/reactivity'
// 可写计算属性(文档有提及但很少被用到)
const count = ref(1)
const plusOne = computed({
get: () => count.value + 1,
set: (val) => { count.value = val - 1 }
})
plusOne.value = 10
console.log(count.value) // 9
三、@vue/runtime-core:平台无关运行时
这是 Vue 组件模型的核心,包含大量未被官方文档重点介绍的底层 API。
3.1 组件内部访问
getCurrentInstance
import { getCurrentInstance } from '@vue/runtime-core'
// 只能在 setup() 或生命周期钩子中调用
const instance = getCurrentInstance()
// 实例上有大量内部属性(仅用于框架级开发,生产代码慎用)
instance.uid // 组件唯一 ID
instance.type // 组件定义对象
instance.parent // 父组件实例
instance.root // 根组件实例
instance.appContext // 应用上下文(含全局注册的组件、指令、插件数据)
instance.subTree // 当前 vnode 子树
instance.isMounted // 是否已挂载
instance.isUnmounted // 是否已卸载
场景:编写需要感知组件树的底层库(如 Pinia 内部通过它访问 appContext)。
useAttrs / useSlots
import { useAttrs, useSlots } from '@vue/runtime-core'
// 在 setup 中访问透传的 attrs 和 slots(等效于选项式 API 的 $attrs/$slots)
const attrs = useAttrs() // 包含 class, style, 事件监听器等非 prop 属性
const slots = useSlots() // 包含所有插槽的渲染函数
useCssModule(与 <style module> 配合)
import { useCssModule } from '@vue/runtime-core'
// 访问 CSS Modules 的类名映射(通常与 SFC <style module> 配合)
const css = useCssModule()
// css.myClass → 'myClass_hash123_1'(编译后的哈希类名)
3.2 依赖注入高级用法
inject 的完整签名与 InjectionKey
import { provide, inject, InjectionKey } from '@vue/runtime-core'
// 使用 Symbol 作为类型安全的注入键(TypeScript 推荐做法)
const UserKey: InjectionKey<{ name: string }> = Symbol('user')
// 父组件
provide(UserKey, { name: 'Tom' })
// 子组件 - 有完整类型推断
const user = inject(UserKey) // User | undefined
const user2 = inject(UserKey, { name: 'Guest' }) // 带默认值,类型为 User
const user3 = inject(UserKey, () => ({ name: 'Guest' }), true) // 工厂函数(第三个参数 true 表示是工厂)
3.3 VNode 操作 API
h 渲染函数的完整能力
import { h, resolveComponent, resolveDirective, withDirectives } from '@vue/runtime-core'
export default {
render() {
// 渲染组件
const MyComp = resolveComponent('MyComp') // 按名称解析已注册的全局组件
// 渲染带自定义指令的 vnode
const dir = resolveDirective('my-directive')
return withDirectives(
h('div', 'hello'),
[[dir, value, argument, modifiers]]
)
}
}
cloneVNode
import { h, cloneVNode } from '@vue/runtime-core'
// 克隆 VNode 并可覆盖部分 props(用于高阶组件 HOC 模式)
const original = h('div', { class: 'foo' }, 'hello')
const cloned = cloneVNode(original, { class: 'bar', style: 'color: red' })
// 等效于 h('div', { class: ['foo', 'bar'], style: 'color: red' }, 'hello')
mergeProps
import { mergeProps } from '@vue/runtime-core'
// 智能合并多个 props 对象(class/style 合并,事件监听器链式调用)
const merged = mergeProps(
{ class: 'a', onClick: handler1 },
{ class: 'b', onClick: handler2 }
)
// { class: ['a', 'b'], onClick: [handler1, handler2] }
这是实现透传属性合并、封装 UI 组件库的核心工具。
createVNode / openBlock / createBlock / createElementVNode
这些是编译器输出的运行时助手函数,通常不应在业务代码中直接使用,但理解它们有助于分析编译产物性能。
// 模板编译后生成的代码示意:
import { createElementVNode, openBlock, createElementBlock } from '@vue/runtime-core'
function render() {
return (openBlock(), createElementBlock("div", null, [
createElementVNode("span", null, "hello")
]))
}
openBlock + createBlock 组合是 Vue 3 **Fragment 优化与靶向更新(patch flag)**的基础。
createTextVNode / createCommentVNode / createStaticVNode
import { createTextVNode, createCommentVNode, createStaticVNode } from '@vue/runtime-core'
createTextVNode('hello') // 创建文本节点
createCommentVNode('debug info') // 创建注释节点(v-if 的占位符就是它)
// createStaticVNode:将静态 HTML 字符串作为 vnode(SSR hydration 场景)
createStaticVNode('<div>static content</div>', 1)
3.4 异步组件
defineAsyncComponent 完整配置
import { defineAsyncComponent } from '@vue/runtime-core'
const AsyncComp = defineAsyncComponent({
loader: () => import('./HeavyComponent.vue'),
loadingComponent: LoadingSpinner, // 加载中显示的组件
delay: 200, // 显示 loading 前的延迟(避免闪烁)
errorComponent: ErrorDisplay, // 加载失败显示的组件
timeout: 3000, // 超时时间(ms),超时视为失败
// 高级:自定义加载函数(控制重试逻辑)
onError(error, retry, fail, attempts) {
if (attempts <= 3) retry() // 最多重试 3 次
else fail()
}
})
3.5 内置组件的底层实现
Suspense 深度用法
import { Suspense, defineAsyncComponent } from 'vue'
<Suspense>
<template #default>
<AsyncComponent />
</template>
<template #fallback>
<LoadingSpinner />
</template>
</Suspense>
Suspense 还支持与 async setup() 配合:
export default {
async setup() {
// setup 可以是异步的,父级 Suspense 会等待它 resolve
const data = await fetch('/api/data').then(r => r.json())
return { data }
}
}
3.6 调度器 API
nextTick 与内部调度机制
import { nextTick } from '@vue/runtime-core'
// nextTick 返回 Promise,可在 DOM 更新后执行操作
await nextTick()
// 也接受回调(兼容旧写法)
nextTick(() => {
// DOM 已更新
})
queuePostFlushCb(内部 API,谨慎使用)
import { queuePostFlushCb } from '@vue/runtime-core'
// 在当前刷新周期结束后异步执行回调(比 nextTick 更底层)
queuePostFlushCb(() => {
// 所有 DOM 更新和 watchPostEffect 之后执行
})
3.7 生命周期扩展钩子
除了常见的八个生命周期,还有以下较少使用的:
import {
onRenderTracked, // 每次响应式依赖被追踪时触发(仅 dev)
onRenderTriggered, // 每次重渲染被触发时携带具体原因(仅 dev)
onActivated, // KeepAlive 激活时
onDeactivated, // KeepAlive 停用时
onServerPrefetch, // SSR:组件 prefetch 数据钩子
onErrorCaptured, // 捕获子孙组件的错误
} from '@vue/runtime-core'
// onRenderTracked / onRenderTriggered 是性能调试利器
onRenderTriggered((event) => {
console.log('触发重渲染的原因:', {
effect: event.effect,
target: event.target, // 被修改的对象
type: event.type, // 'set' / 'add' / 'delete'
key: event.key, // 被修改的属性名
newValue: event.newValue,
oldValue: event.oldValue,
})
})
onRenderTracked 和 onRenderTriggered 是排查不必要重渲染的终极工具,但极少被开发者使用。
3.8 defineComponent 的类型推断能力
import { defineComponent, PropType } from '@vue/runtime-core'
// defineComponent 的核心价值是 TypeScript 类型推断,而非运行时行为
const MyComp = defineComponent({
props: {
user: {
type: Object as PropType<{ name: string; age: number }>,
required: true
},
// 函数类型 prop
onClick: Function as PropType<(id: number) => void>
},
emits: {
// 带类型验证的 emits 定义
change: (value: string) => typeof value === 'string',
submit: null // 无验证
},
setup(props, { emit, expose, attrs, slots }) {
// props 此处有完整类型推断
expose({ publicMethod() {} }) // 限制对外暴露的 API
}
})
3.9 渲染器相关(高级)
createRenderer / createHydrationRenderer
这是 Vue 跨平台渲染的核心 API,允许创建自定义渲染器。
import { createRenderer } from '@vue/runtime-core'
// 创建一个 Canvas 渲染器(伪代码示意)
const { render, createApp } = createRenderer({
createElement(type) { /* 创建 Canvas 元素 */ },
patchProp(el, key, prevVal, nextVal) { /* 更新属性 */ },
insert(el, parent, anchor) { /* 插入节点 */ },
remove(el) { /* 删除节点 */ },
createText(text) { /* 创建文本节点 */ },
setText(node, text) { /* 更新文本 */ },
// ...其他 DOM 操作
})
这是 Pixi.js、Three.js、Native 渲染器等 Vue 跨平台项目的基础 API。
四、@vue/runtime-dom:浏览器平台层
在 runtime-core 之上,runtime-dom 提供了浏览器专属能力。
4.1 内置指令实现
这些通常由编译器自动生成,但在 Render Function 场景下需要手动导入:
import {
vModelText, // <input v-model>
vModelCheckbox, // <input type="checkbox" v-model>
vModelRadio, // <input type="radio" v-model>
vModelSelect, // <select v-model>
vModelDynamic, // 动态类型的 v-model(根据 input type 自动选择实现)
vShow, // v-show
vOn, // v-on 事件监听
vBind, // v-bind
withDirectives, // 应用自定义指令
} from '@vue/runtime-dom'
// 在 render function 中手动使用 v-model
import { h, withDirectives, vModelText } from 'vue'
export default {
setup() {
const text = ref('')
return () => withDirectives(
h('input', { 'onUpdate:modelValue': val => (text.value = val) }),
[[vModelText, text.value]]
)
}
}
4.2 CSS 过渡钩子(内部实现)
import { Transition, TransitionGroup } from '@vue/runtime-dom'
// TransitionGroup 配置详解(文档常被忽视的属性)
h(TransitionGroup, {
name: 'list',
tag: 'ul', // 渲染的包装元素(默认 span)
moveClass: 'move', // FLIP 动画时的 CSS 类名
appear: true, // 初次渲染也触发过渡
css: false, // 禁用 CSS 过渡,纯 JS 控制
onBeforeEnter(el) {},
onEnter(el, done) { /* 必须调用 done() */ },
onLeave(el, done) { /* 必须调用 done() */ },
})
4.3 SSR 相关
import { createSSRApp } from '@vue/runtime-dom'
// SSR hydration:将服务端渲染的 HTML 与 Vue 状态绑定
const app = createSSRApp(App)
app.mount('#app') // 自动检测已有 HTML,进行 hydration 而非全量渲染
五、@vue/compiler-core:编译器核心
这是 Vue 模板编译管道的核心,纯函数式架构,完全平台无关。
5.1 完整编译管道
模板字符串
↓
parse() → AST(抽象语法树)
↓
transform() → 转换 AST(应用各种 transform 插件)
↓
generate() → 渲染函数代码字符串
import { parse, transform, generate, baseParse } from '@vue/compiler-core'
// 解析模板为 AST
const ast = parse('<div>{{ msg }}</div>')
// 对 AST 进行转换(插件化)
transform(ast, {
nodeTransforms: [
// 自定义 transform 插件
(node, context) => {
if (node.type === 1 /* ELEMENT */ && node.tag === 'div') {
// 可以修改 AST,添加、删除、替换节点
}
}
]
})
// 生成代码
const { code } = generate(ast)
console.log(code) // 输出渲染函数字符串
5.2 AST 节点类型(NodeTypes 枚举)
import { NodeTypes } from '@vue/compiler-core'
// 完整节点类型列表(调试 AST 时极为有用)
NodeTypes.ROOT // 0 - 根节点
NodeTypes.ELEMENT // 1 - 元素节点
NodeTypes.TEXT // 2 - 文本节点
NodeTypes.COMMENT // 3 - 注释节点
NodeTypes.SIMPLE_EXPRESSION // 4 - 简单表达式(如 msg、count + 1)
NodeTypes.INTERPOLATION // 5 - 插值({{ }})
NodeTypes.ATTRIBUTE // 6 - 普通属性
NodeTypes.DIRECTIVE // 7 - 指令(v-if、v-for 等)
NodeTypes.COMPOUND_EXPRESSION // 8 - 复合表达式
NodeTypes.IF // 9 - v-if 结构
NodeTypes.IF_BRANCH // 10 - v-if 分支
NodeTypes.FOR // 11 - v-for 结构
NodeTypes.TEXT_CALL // 12
NodeTypes.VNODE_CALL // 13 - createVNode 调用
NodeTypes.JS_CALL_EXPRESSION // 14
NodeTypes.JS_OBJECT_EXPRESSION // 15
NodeTypes.JS_PROPERTY // 16
NodeTypes.JS_ARRAY_EXPRESSION // 17
NodeTypes.JS_FUNCTION_EXPRESSION // 18
NodeTypes.JS_CONDITIONAL_EXPRESSION // 19
NodeTypes.JS_CACHE_EXPRESSION // 20 - 带缓存的表达式(v-once / 静态提升)
5.3 编译优化标记(PatchFlags)
这是 Vue 3 性能优化的核心机制,编译器通过这些标记让运行时的 diff 算法跳过静态内容:
import { PatchFlags } from '@vue/compiler-core'
PatchFlags.TEXT // 1 - 动态文本内容
PatchFlags.CLASS // 2 - 动态 class
PatchFlags.STYLE // 4 - 动态 style
PatchFlags.PROPS // 8 - 动态 props(非 class/style)
PatchFlags.FULL_PROPS // 16 - 有动态键名的 props(如 v-bind="obj")
PatchFlags.HYDRATE_EVENTS // 32 - 含事件监听的节点(SSR hydration 用)
PatchFlags.STABLE_FRAGMENT // 64 - 子节点顺序稳定的 Fragment
PatchFlags.KEYED_FRAGMENT // 128 - 带 key 的 Fragment
PatchFlags.UNKEYED_FRAGMENT // 256 - 无 key 的 Fragment(v-for 无 key 时)
PatchFlags.NEED_PATCH // 512 - 需要 patch 但不在上述分类中
PatchFlags.DYNAMIC_SLOTS // 1024 - 动态插槽
PatchFlags.DEV_ROOT_FRAGMENT // 2048 - dev 模式根节点 Fragment
PatchFlags.HOISTED // -1 - 静态提升节点,永不更新
PatchFlags.BAIL // -2 - 退出优化,进行完整 diff
理解 PatchFlags 是分析 Vue 模板编译产物、进行极致性能优化的必备知识。
5.4 ShapeFlags(组件形态标记)
import { ShapeFlags } from '@vue/shared' // 实际在 shared 包中
ShapeFlags.ELEMENT // 1 - 普通 DOM 元素
ShapeFlags.FUNCTIONAL_COMPONENT // 2 - 函数式组件
ShapeFlags.STATEFUL_COMPONENT // 4 - 有状态组件
ShapeFlags.TEXT_CHILDREN // 8 - children 是文本
ShapeFlags.ARRAY_CHILDREN // 16 - children 是数组
ShapeFlags.SLOTS_CHILDREN // 32 - children 是插槽对象
ShapeFlags.TELEPORT // 64 - Teleport 组件
ShapeFlags.SUSPENSE // 128 - Suspense 组件
ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE // 256
ShapeFlags.COMPONENT_KEPT_ALIVE // 512
ShapeFlags.COMPONENT // 6 - FUNCTIONAL | STATEFUL 的组合
5.5 自定义编译器插件
import { parse, transform, generate, createTransformContext } from '@vue/compiler-core'
// 实现一个自定义 transform:自动给所有 div 添加 data-testid
const myTransform = (node, context) => {
if (node.type === 1 && node.tag === 'div') {
node.props.push({
type: 6, // NodeTypes.ATTRIBUTE
name: 'data-testid',
value: { type: 2, content: 'auto-id' }
})
}
}
const ast = parse('<div><span>hello</span></div>')
transform(ast, { nodeTransforms: [myTransform] })
const { code } = generate(ast, { mode: 'module' })
六、@vue/compiler-dom:浏览器编译器
在 compiler-core 基础上扩展了浏览器专属的处理逻辑。
6.1 @vue/compiler-dom vs @vue/compiler-core
| 能力 | compiler-core | compiler-dom |
|---|---|---|
| 模板解析 | ✅ | ✅(扩展 HTML 实体) |
| v-if / v-for | ✅ | ✅ |
| v-model | 基础实现 | ✅(区分 input/select/checkbox) |
| v-on | 基础实现 | ✅(支持 .stop .prevent 等修饰符) |
| 静态提升 | ✅ | ✅ |
| 内联事件缓存 | ✅ | ✅ |
| SSR 优化 | ❌ | ✅ |
6.2 compile 函数
import { compile } from '@vue/compiler-dom'
// 直接将模板字符串编译为渲染函数代码
const { code } = compile('<div>{{ msg }}</div>', {
mode: 'module', // 'module' | 'function'
prefixIdentifiers: true, // 是否给变量名加前缀
hoistStatic: true, // 静态节点提升
cacheHandlers: true, // 内联事件处理器缓存
ssr: false, // 是否生成 SSR 渲染代码
ssrCssVars: '', // SSR CSS 变量
isNativeTag: (tag) => true, // 判断是否是原生 HTML 标签
isCustomElement: (tag) => tag.includes('-'), // 自定义元素判断
// 编译时优化选项
scopeId: 'data-v-xxxxxx', // Scoped CSS 的 scope ID(SFC 场景)
})
console.log(code)
// import { toDisplayString as _toDisplayString, ... } from "vue"
// export function render(_ctx, _cache) {
// return (_openBlock(), _createElementBlock("div", null, _toDisplayString(_ctx.msg), ...))
// }
七、@vue/shared:内部工具函数
这个包虽然标注为"内部使用",但其中有不少工具函数在框架级开发中很有价值。
import {
EMPTY_OBJ, // Object.freeze({}) — 空对象常量
EMPTY_ARR, // Object.freeze([]) — 空数组常量
NOOP, // () => {} — 空操作函数
NO, // () => false
isArray, // Array.isArray
isMap, // 判断是否为 Map
isSet, // 判断是否为 Set
isDate, // 判断是否为 Date
isRegExp, // 判断是否为 RegExp
isFunction, // typeof val === 'function'
isString, // typeof val === 'string'
isSymbol, // typeof val === 'symbol'
isObject, // val !== null && typeof val === 'object'
isPromise, // isObject(val) && isFunction(val.then)
isPlainObject, // Object.prototype.toString.call(val) === '[object Object]'
extend, // Object.assign
hasOwn, // Object.prototype.hasOwnProperty.call
camelize, // kebab-case → camelCase('on-click' → 'onClick')
capitalize, // 首字母大写
hyphenate, // camelCase → kebab-case(与 camelize 互逆)
toHandlerKey, // 'click' → 'onClick'
looseEqual, // 宽松相等比较(数组、对象深比较,用于 v-model 多选场景)
looseIndexOf, // 使用 looseEqual 的 indexOf
invokeArrayFns, // 批量调用函数数组(生命周期钩子的内部调用方式)
def, // Object.defineProperty 封装
toRawType, // Object.prototype.toString 取类型名('Map', 'Set', 'Array' 等)
makeMap, // 从字符串创建成员检测函数(HTML 标签白名单等场景)
} from '@vue/shared'
// makeMap 示例:
const isHTMLTag = makeMap('div,span,p,a,img,ul,li,...')
isHTMLTag('div') // true
isHTMLTag('my-comp') // false
八、完整包导出结构总览
Vue 3 包生态
│
├── @vue/reactivity(独立响应式)
│ ├── 核心:ref, reactive, computed, watch
│ ├── 浅层:shallowRef, shallowReactive, shallowReadonly
│ ├── 副作用:effect, effectScope, getCurrentScope, onScopeDispose
│ ├── 追踪控制:pauseTracking, resumeTracking, resetTracking
│ ├── 工具:toRaw, markRaw, proxyRefs, triggerRef, customRef
│ ├── 类型判断:isRef, isReactive, isReadonly, isProxy, isShallow
│ └── 转换:toRef, toRefs, toValue, unref
│
├── @vue/runtime-core(核心运行时)
│ ├── 应用:createApp(通过 runtime-dom 暴露)
│ ├── 组件:defineComponent, defineAsyncComponent
│ ├── VNode:h, createVNode, cloneVNode, mergeProps, createTextVNode
│ ├── 编译助手:openBlock, createBlock, createElementBlock(内部)
│ ├── 实例:getCurrentInstance, useAttrs, useSlots, useCssModule
│ ├── 注入:provide, inject, InjectionKey
│ ├── 生命周期:onMounted...onUnmounted, onRenderTracked, onRenderTriggered
│ ├── 调度:nextTick, queuePostFlushCb
│ ├── 渲染器:createRenderer, createHydrationRenderer
│ └── 内置组件:Suspense, KeepAlive, Teleport(定义在此)
│
├── @vue/runtime-dom(浏览器运行时)
│ ├── 应用:createApp, createSSRApp, render, hydrate
│ ├── 指令实现:vModelText, vModelCheckbox, vShow 等
│ ├── 过渡:Transition, TransitionGroup
│ └── 重新导出:全部 runtime-core 导出
│
├── @vue/compiler-core(编译器核心)
│ ├── 编译管道:parse, transform, generate
│ ├── 枚举:NodeTypes, PatchFlags, ElementTypes
│ ├── 工具:createTransformContext, traverseNode
│ └── 助手:createSimpleExpression, createCallExpression 等
│
├── @vue/compiler-dom(浏览器编译器)
│ ├── 顶层:compile(模板字符串 → 渲染函数代码)
│ └── 重新导出:全部 compiler-core 导出
│
└── @vue/shared(内部工具)
├── 类型判断:isArray, isFunction, isObject, isPromise...
├── 字符串:camelize, hyphenate, capitalize, toHandlerKey
├── 标志:ShapeFlags, PatchFlags(部分)
└── 工具:makeMap, extend, hasOwn, looseEqual, invokeArrayFns
九、架构层次与使用建议
| 包 | 适用场景 | 是否可独立使用 |
|---|---|---|
@vue/reactivity |
非 UI 的响应式状态管理 | ✅ 完全独立 |
@vue/runtime-core |
自定义渲染器 | ✅ 需搭配自定义渲染器 |
@vue/runtime-dom |
浏览器 Vue 应用 | ✅ 等价于 vue(无编译器) |
@vue/compiler-core |
构建工具插件、代码转换 | ✅ 独立使用 |
@vue/compiler-dom |
运行时模板编译(少用) | ✅ 独立使用 |
@vue/shared |
框架级工具函数 | ⚠️ 内部包,API 随版本变化 |
vue |
标准应用开发 | ✅ 聚合所有能力 |
十、总结
Vue 3 的包体系围绕关注点分离构建:
-
响应式 与 渲染 完全解耦,
@vue/reactivity可独立运行 -
平台无关运行时 与 浏览器平台实现 分离,
createRenderer支持跨平台 -
编译器 同样分层,
compiler-core可扩展用于 Vite 插件、Babel 转换等 -
PatchFlags和effectScope等低层 API 是框架性能优化的真正秘密
理解这套架构,不仅能写出更高质量的组合函数和 UI 组件库,也能在需要时深入框架层进行扩展——这是从"会用 Vue"到"精通 Vue 架构"的关键跨越。