Vue 3 源码学习教程
一、准备工作
| 步骤 | 命令/操作 |
|---|---|
| 克隆源码 | git clone https://github.com/vuejs/core.git |
| 切换分支 | git checkout main |
| 安装依赖 | pnpm install |
| 打包 | pnpm build |
环境要求: Node.js 16+,pnpm 7+
二、源码目录结构
packages/
├── reactivity/ # 响应式系统(面试重点)
├── runtime-core/ # 运行时核心(渲染、组件)
├── runtime-dom/ # 浏览器运行时(DOM操作)
├── compiler-core/ # 编译器核心(模板编译)
├── compiler-dom/ # 浏览器编译器
├── vue/ # 入口,整合所有模块
├── shared/ # 工具函数
学习顺序: reactivity → runtime-core → compiler-core(可选)→ vue
三、各文件夹详细介绍
1. packages/reactivity(响应式系统)
| 文件 | 作用 | 面试重点 |
|---|---|---|
reactive.ts |
reactive 实现,用 Proxy 代理对象 | ✅ 核心 |
ref.ts |
ref 实现,包装基本类型 | ✅ 核心 |
effect.ts |
依赖收集、触发更新的核心 | ✅ 核心 |
computed.ts |
计算属性 | ⚠️ 了解 |
watch.ts |
watch 实现 | ⚠️ 了解 |
需要掌握:
- reactive 如何用 Proxy 代理
- 依赖收集(track)和触发更新(trigger)流程
- ref 和 reactive 的区别
- effect 的作用
2. packages/runtime-core(运行时核心)
| 文件/目录 | 作用 | 面试重点 |
|---|---|---|
component.ts |
组件定义、生命周期 | ⚠️ 了解 |
renderer.ts |
渲染器,负责创建、更新、删除节点 | ✅ 核心 |
vnode.ts |
虚拟 DOM 定义 | ✅ 核心 |
scheduler.ts |
异步更新队列(nextTick 相关) | ✅ 核心 |
apiLifecycle.ts |
生命周期钩子 | ⚠️ 了解 |
需要掌握:
- 渲染流程:mount → patch → update
- diff 算法:同层比较、key 的作用
- nextTick 原理:微任务队列
3. packages/runtime-dom(浏览器运行时)
| 文件 | 作用 |
|---|---|
index.ts |
入口,导出 createApp 等 |
nodeOps.ts |
浏览器 DOM 操作(createElement、insert 等) |
patchProp.ts |
属性更新(class、style、事件) |
需要掌握: 知道这是浏览器专属层,负责 DOM 操作即可。
4. packages/compiler-core(编译器核心)
| 文件 | 作用 |
|---|---|
parse.ts |
模板解析成 AST |
transform.ts |
转换 AST |
codegen.ts |
生成 render 函数 |
需要掌握: 了解编译流程:parse → transform → codegen,不用深究细节。
5. packages/vue(入口)
| 文件 | 作用 |
|---|---|
index.ts |
导出所有公共 API |
runtime.ts |
只包含运行时(不含编译器) |
runtime+compiler.ts |
包含编译器 |
需要掌握: 知道这是打包入口,导出 createApp、ref、reactive 等即可。
6. packages/shared(工具函数)
| 文件 | 作用 |
|---|---|
shapeFlags.ts |
虚拟 DOM 类型标记 |
patchFlags.ts |
更新优化标记 |
general.ts |
通用工具函数 |
需要掌握: 不用深究,知道有工具函数即可。
四、学习路线(30天版)
| 阶段 | 时间 | 内容 | 目标 | 每天用时 |
|---|---|---|---|---|
| 阶段一 | 第1-7天 | reactivity 模块 |
能讲响应式原理 | 2小时 |
| 阶段二 | 第8-14天 | runtime-core 渲染流程 |
能讲 mount、patch | 2小时 |
| 阶段三 | 第15-21天 | diff 算法 + scheduler |
能讲 diff、nextTick | 2小时 |
| 阶段四 | 第22-28天 | 过一遍面试题 + 手写简易版 | 能写 demo | 2小时 |
| 阶段五 | 第29-30天 | 整体复盘 + 模拟面试 | 能流畅表达 | 2小时 |
五、调试技巧
1. 创建测试项目
# 在 packages/vue 目录下创建测试文件
cd packages/vue
touch test.js
2. 测试代码示例
// test.js
import { createApp, ref, reactive } from './dist/vue.js'
const app = createApp({
setup() {
const count = ref(0)
const state = reactive({ name: 'vue' })
return { count, state }
},
template: `<div>{{ count }} - {{ state.name }}</div>`
})
app.mount('#app')
3. 打断点调试
-
在 VS Code 中打开源码
-
在关键行打断点(如 reactive.ts 中的 track 函数)
-
运行测试文件,查看调用栈
六、面试话术模板
1. 被问响应式原理
"我看过 Vue 3 源码的 reactivity 模块。reactive 是用 Proxy 代理对象,在 get 中通过 track 收集依赖,在 set 中通过 trigger 触发更新。ref 是对基本类型的包装,通过一个对象来存储值,同样用
track 和 trigger 管理依赖。"
2. 被问渲染流程
"从 runtime-core 的 renderer.ts 可以看到,首次渲染调用 mount,创建虚拟 DOM 并挂载。更新时调用 patch,对比新旧虚拟 DOM。patch 里会判断节点类型,如果是同一节点就走 patchElement 更新属性,
如果不是就替换。"
3. 被问 diff 算法
"diff 在同层比较,不跨层。用 patchChildren 处理子节点,分几种情况:新旧都是文本、新旧都是数组。如果是数组,会用双端比较算法,优化常见操作(头部插入、尾部插入、反转)。key 的作用是标识节
点,方便复用。"
4. 被问 nextTick
"nextTick 的源码在 scheduler.ts 里。它把回调加入一个队列,然后用微任务(Promise.then)异步执行。这样可以避免多次更新重复渲染,把多次修改合并成一次。"
七、手写简易版练习
1. 手写简易 reactive
function reactive(obj) {
return new Proxy(obj, {
get(target, key) {
track(target, key)
return target[key]
},
set(target, key, value) {
target[key] = value
trigger(target, key)
return true
}
})
}
2. 手写简易 ref
function ref(value) {
return {
_value: value,
get value() {
track(this, 'value')
return this._value
},
set value(newVal) {
this._value = newVal
trigger(this, 'value')
}
}
}
八、常见面试题
| 问题 | 答案要点 |
|---|---|
| Vue 3 响应式怎么实现的? | Proxy + 依赖收集 |
| reactive 和 ref 区别? | reactive 代理对象,ref 包装基本类型 |
| 依赖收集怎么做的? | get 中 track,set 中 trigger |
| nextTick 原理? | 微任务队列,异步更新 |
| diff 算法怎么优化? | 同层比较、双端比较、key |
| 组件更新过程? | 触发更新 → 重新渲染 → diff → 打补丁 |
九、学习资源
| 资源 | 链接 |
|---|---|
| Vue 3 源码 | https://github.com/vuejs/core |
| 官方文档 | https://vuejs.org/ |
| 源码分析文章 | https://vue3js.cn/start/ |
| 手写简易版视频 | B站搜索"Vue3 源码 手写" |
十、结论
按这个教程走,30天足够应付面试。
每天2小时,边看源码边写 demo,一个月后您就能自信地说:"我看过 Vue 3 源码。"