vue.js 设计与实现-vue3源码学习(1)

536 阅读3分钟

前言

今年初就准备学习 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. 打包报错

image.png 解决方案 "build": "node --max_old_space_size=8192 scripts/build.js"

image.png

如果出现 Error: Cannot find module 'fs-extra 该报错 安装一下依赖包 npm install -g fs-extra 如如果还是报错,把依赖包删除掉,通过 pnpm install 再安装依赖

3. npm run build 打包 打包完成后会在 packages/vue/dist 中生成代码

image.png
我们来测试一下打包的结果,定义一个html文件,引入我们刚打包好的 js。我们起个服务运行 html 在vscode 中安装该插件。右键html 可以进行Live Server

image.png

<!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 都可以

image.png 为什么这么加呢? 打包时运行的是 scripts 文件夹下的 build.js 我们来看下这个文件

image.png

const args = require('minimist')(process.argv.slice(2)) minimist 可以拿到我们控制台里面的参数 sourceMap 的值根据我们配置的 sourcemap 或 s 取值。 有兴趣的小伙伴可以去了解一下 minimist 的用法。

最后

此时准备已经全部完成,下篇我们开始一步步来深入了解其中的奥秘吧!