前言
今年初就准备学习 vue3 的源码,但手里又有很多事情要做,一直忙着,现在终于抽出时间来开始学习了。本系列会根据 vue3 源码来一步步实现一个简易版的 vue3 框架。希望在学习中能够加深对 vue 的理解,拓展自己思考问题的思路,进而提高自己的代码水平。
目前是一边看 《vue.js 设计与实现》 一边学习源码。在开始之前先了解几个概念
1 命令式与声明式
命令式: 注重过程,为实现某个结果而进行的一系列步骤,每个细节都有详细的描述。如我想把大象放冰箱,则分三步,打开冰箱,把大象放进去,关上冰箱,一步步实现我们想要的结果。
声明式: 注重结果,不在意过程与细节。如我想把大象放冰箱,怎么放我不关注,你给我个工具,我能直接用就行。
优缺点对比: 声明式代码的性能不优于命令式代码的性能。相对来说命令式的性能高,维护性差,声明式性能低,但可维护性高。举个栗子 修改页面的文本,命令式是直接处理修改,而声明式是对比差异后再进行处理修改,中间多了一步对比差异,这也就导致 声明式代码的性能不优于命令式代码的性能 1 <= 1 + x ( x >= 0)
2 编译时与运行时
编译时: 如 vue 中 template 模板,我们直接写 html 元素,vue 框架会帮我们进行编译成它所需要的 dom 结构,然后使用 render 函数进行 dom 渲染。
运行时:render 函数 h('div',{id:'div'},"我是运行时的节点")。运行时代码直接使用,无须再编译。
完成页面渲染的流程 编译?->运行->渲染
vue采用的方式 运行时+编译时 取两者之长,我们可以在 template 中使用模板渲染也可以在 scriprt 中写 render 函数来进行函数编译。
vue3源码的准备工作
clone 代码
学习源码时选用的是3.2.37 github.com/vuejs/core/…
安装依赖
推荐 pnpm 安装依赖,因为之前用 npm 发现无法打包,排查问题比较麻烦,yarn 目前没试过。
踩坑问题
1. npm node 版本较低
目前维护的还有老项目,node 版本切换着用,安装了14x.16x.18.几个,该源码系列采用 16.18.0 。记得当时报错时npm 版本是8.x 提示要更新,然后根据提示更新到了 9.6.4。
使用 nvm 进行 node 版本切换。之前文章有聊过 juejin.cn/post/720499…
2. 打包报错
解决方案
"build": "node --max_old_space_size=8192 scripts/build.js"
如果出现 Error: Cannot find module 'fs-extra 该报错 安装一下依赖包 npm install -g fs-extra 如如果还是报错,把依赖包删除掉,通过 pnpm install 再安装依赖
3. npm run build 打包
打包完成后会在 packages/vue/dist 中生成代码
我们来测试一下打包的结果,定义一个html文件,引入我们刚打包好的 js。我们起个服务运行 html
在vscode 中安装该插件。右键html 可以进行Live Server
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../dist/vue.global.js"></script>
</head>
<body>
<div id="app"></div>
<button onclick="changeName()">修改数据</button>
</body>
<script>
const { reactive ,effect}=Vue
const obj=reactive({
name:'provens'
})
//响应式数据更新,我们后面再聊
effect(()=>{
document.getElementById("app").innerHTML=obj.name
})
const changeName=()=>{
obj.name=obj.name==="我还是provens 啊"?'我是修改的数据啊':'我还是provens 啊'
}
</script>
</html>
4. 添加sourcemap
我们运行以上代码是经过压缩的代码无法进行 debugger 的,我们在 package.json 里面添加配置
--sourcemap 或者 -s 都可以
为什么这么加呢? 打包时运行的是
scripts 文件夹下的 build.js 我们来看下这个文件
const args = require('minimist')(process.argv.slice(2))
minimist 可以拿到我们控制台里面的参数 sourceMap 的值根据我们配置的 sourcemap 或 s 取值。
有兴趣的小伙伴可以去了解一下 minimist 的用法。
最后
此时准备已经全部完成,下篇我们开始一步步来深入了解其中的奥秘吧!