Vue3 源码学习指南
# 为什么学习源码
- 技术是
第一生产力
- 学习 API 的设计目的、
思路
、取舍 - 学习优秀的
代码风格
- 学习组织代码的方式
- 学习实现方法的技巧
- 学习 ES6+ 新 API、TS 高级用法
- 不给自己设限,不要让你周围人的技术上限成为你的上限
面试加分项
- 装逼利器
# vue3 VS vue2
# 优化
- 打包更小(全局
API tree-shaking
) - 渲染、更新更快,内存占用减少
- 使用
proxy
取代Object.defineProperty
v-model
代替以前的v-model
和.sync
- 生命周期变更 例如
beforeDestroy
,destroyed
改为beforeUnmount
,unmounted
- 自定义指令 API 与生命周期保持一致
- Diff 算法的提升(静态标记、静态提升)
# 新特性
Template
支持多个根标签composition
API
实现逻辑模块化和复用Teleport
传送门组件 代码块挂载到任意位置Suspense
悬停组件 异步加载组件使用(实验属性)- 使用
@vue/runtime-core
的createRenderer
自定义渲染器(跨平台利器) - 使用 ts 编写源码,更好的类型推导、更好的适配 ts
# 更多变化
# 疑惑解答
# compostion api 根本没有解决任何问题,只是追逐新玩意的东西
尤雨溪
: 不同意这个观点。 Vue 最开始很小,但是现在被广泛应用到不同级别复杂度的业务领域,有些可以基于 option API 很轻松处理,但是有些不可以。例如下面的场景:
- 有很多逻辑的大型组件(数百行)
- 在多个组件可复用的逻辑
对于问题 1,你需要把每个逻辑拆分到不同选项,例如,一段逻辑需要一些响应数据,一个计算属性,一些监听属性还有方法。你去了解这段逻辑时,需要不断上下移动阅读,虽然你知道一些属性是什么类型,但是你并不知道他具体的作用。当一个组件包含多个逻辑,情况就更糟糕了。如果用新的 API,可以将数据和逻辑组合在一起,最重要的是,你可以干净的把这些逻辑提取到一个函数,甚至一个单独的文件中。
# 使用新 API 导致逻辑分散到不同地方,违背"关注点分离"
尤雨溪
: 这个问题和项目文件组织方式问题类似。我们很多人都同意按文件类型组织(布局放 HTML,样式 CSS,逻辑 JS)并不是正确的方式,因为强制把相关代码分割到三个文件,只是给人一种“关注点分离”的错觉。这里的关键是“关注点”不是 由文件类型定义。相反,我们大多数选择以 功能或者职责来组织文件,这正是人们喜欢 Vue 单文件组件的原因。SFC 就是按功能组织代码的方法,但讽刺的是当首次引入 SFC 时,许多人也是拒绝的,认为它违反了关注点分离。
# 新的语法让 Vue 失去简单性,导致"意大利面条式代码"的出现,降低项目维护性。
尤雨溪
: 正好相反,新的 API 就是为了提高项目长期维护性的。如果我们查看任何 javascript 项目,都会从入口文件开始阅读,该文件的本质是你的应用启动时被隐式调用的"main"函数。如果只有一个函数入口,会导致意大利面条代码,那所有的 js 项目都是意大利面条代码。显然不是的,因为开发人员通过代码模块化或者较小的函数来组织代码。另外,我同意新的 API 理论上会降低代码质量的最低门槛。但是我们可以使用以往防止代码变成意大利面条的手段缓解这种情况。另一方面,新的 API 可以提升代码质量的最高上限
,相比 option api,你可以重构为质量更高的代码。而且,基于 Option api 你还得解决类似 mixins 的问题。很多人认为"Vue 失去简单性",实际上只是失去组件内代码类型检查能力(就是你不知道一个变量时 data、method、还是 computed)。但是用新的 API,实现一个类型检测器也是非常容易实现以前的特性的。也就是说,`你不应该被 option api 限制思维,而更多关注逻辑内聚问题
# 源码调试
1、克隆源码及安装依赖
现在阅读 Vue3 源码版本是 3.2.23
,安装依赖使用 pnpm (opens new window)
git clone https://github.com/vuejs/vue-next.git
pnpm install
yarn dev --sourcemap
2
3
2、新建 packages/vue/examples/index.html 用于测试
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<div>
<div>test demo {{msg}}</div>
<div>test demo {{msgMore}}</div>
</div>
</div>
<script src="../dist/vue.global.js"></script>
<script>
Vue.createApp({
setup() {
const msg = Vue.ref('Hello')
const msgMore = Vue.computed(()=>msg.value+' world')
return {
msg,
msgMore
}
}
}).mount('#app')
</script>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
3、在vscode 安装 live server 插件,打开浏览器开发者工具调试