大白话Vue源码系列(01):万事开头难

时间:2022-09-26 09:43:33

Angular 是 Google 亲儿子,React 是 Facebook 小正太,那咱为啥偏偏选择了 Vue 下手,一句话,Vue 是咱见过的最对脾气的 MVVM 框架。之前也使用过 knockout,angular,react 这些框架,但都没有让咱产生 follow 的冲动。直到见到 Vue,简直是一见钟情啊。

Vue 的官方文档已经对 Vue 如何使用提供了最好的教程,建议 Vue 新手直接去官网学习,而不要在网上找些质量参差不齐的文档去看,以免误人子弟。中文版英文版 文档写的都很地道,毕竟是国产,中文文档真心赞。不夸张地说,中文文档咱已经看了不下 5 遍了,每次都有收获,第一遍看的很慢,边看边做,之后就非常快了,主要都是扫读。英文的咱也不是看不了,只是速度问题,没必要较这个劲。值得一提的是,Vue 每次版本更新官方文档迅速都会跟进到最新,所以说 Vue 的官方文档是学习 Vue 的不二之选。

本系列的目的不是介绍如何使用 Vue,而是希望把 Vue 的源码实现思路简单清晰地描绘出来,从而摸清一个 MVVM 框架是如何工作的,并从中学习封装*(库或框架)的各种实用技巧。文章中的不足和欠缺之处,请大家多多指教/抱拳。

Vue 版本:2.5.9

Vue 的源码目录结构

如果直接去看 Vue 生成的代码文件 Vue.js,代码足足有上万行。这样去研究源码肯定是行不通的,也是不明智的。从 Vue 项目的目录结构入手是个不错的选择,这么大的项目,一个好的目录结构对开发和维护的重要性不言而喻。

Vue 源码目录如下:

大白话Vue源码系列(01):万事开头难

Vue 源码目录

各目录和文件功能:

  • compiler
    此目录存放编译模板相关的代码,用于将 html 模板编译成 Vue 的 render 函数
  • runtime
    此目录存放 Vue 生命周期内使用的相关代码,负责 Vue 实例的创建,视图渲染和处理虚拟 DOM 等等一切编译 html 模板之外的事情。
  • server
    这里存放 Vue 服务端渲染(SSR)需要使用的代码。
  • util
    这里存放一些其他模块共用的工具函数。
  • entry-compiler.js
    该文件是一个提供编译 html 模板相关接口的模块,通常用于为 Vue 编写的构建插件,比如 vue-loadervueify
  • entry-runtime.js
    用于构建仅包含运行时的文件,不具备编译 html 模板功能。
  • entry-runtime-with-compiler.js
    用于构建同时包含编译器和运行时的全功能文件。
  • entry-server-basic-renderer.js 和 entry-server-renderer.js
    用于构建服务端渲染可用的文件。

可见 Vue 按照功能块对整个项目进行了目录拆分,每个目录负责一块功能,接下来就可以从这些 entry 文件入手按照 模块依赖 进行由浅及深,从整体到局部的深入剖析。

在继续之前咱们可以先看一下由上面这些源代码构建出来的可用文件是怎么样的。

Vue 构建生成的目录如下:

大白话Vue源码系列(01):万事开头难

Vue 构建生成的目录

各文件功能:

UMD CommonJS ES Module
Full vue.js vue.common.js vue.esm.js
Runtime-only vue.runtime.js vue.runtime.common.js vue.runtime.esm.js

表格中的术语解释:

  • Full:包含编译器和运行时的全部功能。
  • Runtime-only:仅包含运行时。
  • UMD:可通过 <script> 标签引入直接在浏览器中使用,Vue 会暴露一个全局变量 window.Vue。同时适配 require.js 这种 AMD 系统的使用。
  • CommonJS:适配 const Vue = require('vue') 这种 node 式的模块系统。
  • ES Module:适配 import Vue from 'vue' 这种 es6 提供的模块系统。

这些被构建出来的文件才是咱们在实际项目中可以直接使用的文件。

是用 Full 还是用 Runtime-only ?
这个需要具体情况具体分析。如果你需要使用 Vue 提供的 html 模板功能,那么就使用 Full 版本。否则,最好用 Runtime-only 版本,因为它比 Full 版本的文件体积会小上 30% 左右。值得注意的是,*.vue 单文件组件会被 vue-loader 或 vueify 直接构建成 JavaScript,并没有使用到 Vue 的编译器,因此可使用 Runtime-only 版本。

预备知识

# Flow

Vue 使用了 Facebook 出品的 flow.js 作为静态类型检查工具,所以特意跑到 flow 的官网了解了一下(不然看到一些奇怪的写法会一脸懵逼),发现其实很简单,就是在变量或函数签名的地方加上一些类型注解,而且都是可选项,加不加都行,主要是为了方便开发维护用的。

为什么选择 FLow 而不是 TypeScript ?
Vue 是想找一个静态类型检查工具以便提高项目的开发效率和可维护性。Flow 和 TypeScript 都提供了静态类型检查功能,但 TypeScript 提供了更多的有用功能,静态类型检查只是 TypeScript 提供的诸多强大功能里并不起眼的一个。而 Flow 则不一样,静态类型检查几乎是它的全部,可以说是典型小而美的实现。可能是本着杀鸡焉用牛刀,尽可能降低项目复杂度的想法,Vue 选择了 Flow 而不是 TypeScript。无独有偶,Vue 的构建工具选择了 rollup 而不是 webpack,原因应该也是如出一辙。所以说最强的不一定是最好的,最合适的才是最好的。

# ES6

Vue 的源码完全使用 ES6 编写,使得代码更清晰,更易维护。本系列的所有代码片段亦全部使用 ES6,不熟悉 ES6 的同学是时候加强学习了,这可是 JavaScript 的未来。如果想系统了解一下 ES6 的话推荐阮一峰老师的 ECMAScript 6 入门 教程。

# Rollup

Vue 使用了 Rollup 作为最后的打包工具。并且使用了 Rollup 的 rollup-plugin-alias 插件,该插件可以为目录取一个别名,使得在编写 ES6 代码 import 模块时可以使用更短的路径,而不用每次都小心翼翼地去拼相对路径,非常方便。如果不了解这一点,在看到 import config from 'core/config' 这种语句时可能会很迷惑,同级目录下并没有 core 目录啊,实际上 core 是 Vue 为其他目录配置的别名。这个映射表可以在 build/alias.js 文件中找到,映射表中有一条 core: resolve('src/core')resolve('src/core') 会解析出 core 目录的绝对路径,这其实就是告诉 rollup 在解析 import config from 'core/config' 时从这个绝对目录中去加载 config.js

先捡软的捏

从源码的目录结构可以看出,Vue 的 runtime 模块负责的事情很多,代码量必然也很大,应该是块难啃的骨头。而 compiler 则只负责将 html 模板转换为 Vue 的 render 函数,这一块应该是水很浅的,因此从这块入手先吃掉它一部分。

本系列将以每周一篇的速度定时更新,喜欢的小伙伴可以点推荐哦。

大白话Vue源码系列(01):万事开头难的更多相关文章

  1. 大白话Vue源码系列&lpar;03&rpar;:生成AST

    阅读目录 AST 节点定义 标签的正则匹配 解析用到的工具方法 解析开始标签 解析结束标签 解析文本 解析整块 HTML 模板 未提及的细节 本篇探讨 Vue 根据 html 模板片段构建出 AST ...

  2. 大白话Vue源码系列&lpar;02&rpar;:编译器初探

    阅读目录 编译器代码藏在哪 Vue.prototype.$mount 构建 AST 的一般过程 Vue 构建的 AST 题接上文,上回书说到,Vue 的编译器模块相对独立且简单,那咱们就从这块入手,先 ...

  3. 大白话Vue源码系列&lpar;03&rpar;:生成render函数

    阅读目录 优化 AST 生成 render 函数 小结 本来以为 Vue 的编译器模块比较好欺负,结果发现并没有那么简单.每一种语法指令都要考虑到,处理起来相当复杂.上篇已经生成了 AST,本篇依然对 ...

  4. 大白话Vue源码系列&lpar;04&rpar;:生成render函数

    阅读目录 优化 AST 生成 render 函数 小结 本来以为 Vue 的编译器模块比较好欺负,结果发现并没有那么简单.每一种语法指令都要考虑到,处理起来相当复杂.上篇已经生成了 AST,本篇依然对 ...

  5. 大白话Vue源码系列&lpar;05&rpar;:运行时鸟瞰图

    阅读目录 Vue 实例的生命周期 实例创建 响应的数据绑定 挂载到 DOM 节点 结论 研究 runtime 一边 Vue 一边源码 初看 Vue 是 Vue 源码是源码 再看 Vue 不是 Vue ...

  6. 大白话Vue源码系列目录

    .first-level{ font-size: 1.2rem; cursor: default; color: #666; } .second-level{ font-size: 1.1rem; p ...

  7. 手牵手,从零学习Vue源码 系列一(前言-目录篇&rpar;

    系列文章: 手牵手,从零学习Vue源码 系列一(前言-目录篇) 手牵手,从零学习Vue源码 系列二(变化侦测篇) 手牵手,从零学习Vue源码 系列三(虚拟DOM篇) 陆续更新中... 预计八月中旬更新 ...

  8. 手牵手,从零学习Vue源码 系列二(变化侦测篇)

    系列文章: 手牵手,从零学习Vue源码 系列一(前言-目录篇) 手牵手,从零学习Vue源码 系列二(变化侦测篇) 陆续更新中... 预计八月中旬更新完毕. 1 概述 Vue最大的特点之一就是数据驱动视 ...

  9. VUE 源码学习01 源码入口

    VUE[version:2.4.1] Vue项目做了不少,最近在学习设计模式与Vue源码,记录一下自己的脚印!共勉!注:此处源码学习方式为先了解其大模块,从宏观再去到微观学习,以免一开始就研究细节然后 ...

随机推荐

  1. HashMap和HashSet

    Java使用Set接口来描述集合,而Set中每一个数据元素都是唯一的. HashSet散列集合 Hash算法:把任意长度输入,通过散列算法,变换成固定长度的输出即散列值.对不同类型信息,散列值公式也是 ...

  2. 解决 Visual Studio 2012 有时不能调试的问题

    有时候发现 Visual Studio 2012 不能调试,有时候又能调试.感觉很烦,今天找到了一个解决办法,我也不知道为什么这样能解决. 问题: 解决:1. 找到 Properties ,双击 2. ...

  3. StringBuffer&amp&semi;StringBuilder

    对字符串修改时,用到StringBuffer&StringBuilder,能够多次修改对象并且不产生新的未使用对象 StringBuilder线程不安全(不能同步访问),速度有优势,多数情况下 ...

  4. JAVA之Mybatis基础入门二 -- 新增、更新、删除

    上一节说了Mybatis的框架搭建和简单查询,这次我们来说一说用Mybatis进行基本的增删改操作: 一. 插入一条数据 1.首先编写USER.XML(表的xml)使用insert元素,元素写在map ...

  5. 从零开始学 Web 之 CSS3(二)颜色模式,文字阴影,盒模型,边框圆角,边框阴影

    大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公众号:Web前端之巅 博客园:ht ...

  6. 安装babel遇到的异常

    Error: Requires Babel "^7.0.0-0", but was loaded with "6.26.3". If you are sure ...

  7. Java基础——iO(三)

    一.管道流 演示:PipedInputStream  , PipedOutputStream 注意:管道流本身就不建议在一个线程中使用,这是因为向输出流中写的数据,都会存到输入流内部的一个1024字节 ...

  8. 在shell中使用sed命令替换&sol;为&bsol;&sol;

    sed命令相关: https://www.cnblogs.com/ggjucheng/archive/2013/01/13/2856901.html https://www.cnblogs.com/D ...

  9. learn go ifelse

    package main // 参考文档: // https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/05.1.md im ...

  10. LeetCode——Max Consecutive Ones

    LeetCode--Max Consecutive Ones Question Given a binary array, find the maximum number of consecutive ...