阅读视图

发现新文章,点击刷新页面。

深入解析 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 响应式系统最底层的副作用原语computedwatch 都是基于它构建的。

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,
  })
})

onRenderTrackedonRenderTriggered 是排查不必要重渲染的终极工具,但极少被开发者使用。


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 转换等
  • PatchFlagseffectScope 等低层 API 是框架性能优化的真正秘密

理解这套架构,不仅能写出更高质量的组合函数和 UI 组件库,也能在需要时深入框架层进行扩展——这是从"会用 Vue"到"精通 Vue 架构"的关键跨越。

❌