Vue 源码学习 (1) - 起始篇
一. 写在前面
作为前端开发, Vue
是我日常工作中使用最多的框架,各种特性我都有进行了解。但是对于框架底层的原理却知之甚少,知道数据劫持,但是不知道依赖收集的具体过程。知道 diff
算法,但对 Vue
所做的算法优化不了解。一入门就学习了 Vue
的生命周期,却不了解组件实例化的整个过程。
总的来说就是似懂非懂,都知道一些,都不深入。因此学习源码,了解 Vue
的整体设计是我的主要目标。也希望通过 Vue
源码的学习能让我在工作中使用 Vue
更加的得心应手。
二. 基本介绍
Vue
的源码设计的东西太多了,我决定拆分成不同部分去阅读,带有目的去了解。
- 源码地址: https://github.com/vuejs/vue
- 分支: main
- 版本: v2.7.0
这里选择了当前(2022-06)最新版本的代码,当前版本的代码已经全部使用 TypeScript
进行重写,舍弃了之前的 flow
标注,阅读体验还是比较好的。
Vue
的代码在 src
目录下,目录结构为
src
├── compiler # 编译相关
├── core # 核心代码
├── platforms # 多平台支持
├── server # 服务端
├── types # 类型声明
├── shared # 共享工具方法
├── v3 # v3 的特性
看源码的顺序一般从入口文件开始, Vue
作为库,入口文件是它的构建产物,因此我们从打包命令中入手。
"build": "node scripts/build.js",
于是找到 scripts/build.js
文件,然后找到配置文件 scripts/config.js
const builds = { // Runtime only (CommonJS). Used by bundlers e.g. Webpack & Browserify 'runtime-cjs-dev': { entry: resolve('web/entry-runtime.ts'), dest: resolve('dist/vue.runtime.common.dev.js'), format: 'cjs', env: 'development', banner }, 'runtime-cjs-prod': { entry: resolve('web/entry-runtime.ts'), dest: resolve('dist/vue.runtime.common.prod.js'), format: 'cjs', env: 'production', ...
从上面的配置中,我们可以看到 Vue
在打包是构建成不同的版本,有支持 CommonJS
规范 cjs
,
也有支持 ESM
的 esm
, 也有兼容多格式的 UMD
。其中有带 complier
的版本,也有 runtime-only
的版本。
三. 入口文件
从配置文件中有找到 别名的声明文件 scripts/alias
{ vue: resolve('src/platforms/web/entry-runtime-with-compiler'), }
也有很多的构建版本以该文件作为入口文件,因此从 src/platforms/web/entry-runtime-with-compiler.ts
开始入手。
import Vue from './runtime-with-compiler' import * as vca from 'v3' import { extend } from 'shared/util' extend(Vue, vca) import { effect } from 'v3/reactivity/effect' Vue.effect = effect export default Vue
忽略新增的 v3
的功能代码,进入 ./runtime-with-compiler
文件
const mount = Vue.prototype.$mount Vue.prototype.$mount = function () { const { render, staticRenderFns } = compileToFunctions(...) options.render = render options.staticRenderFns = staticRenderFns }
这个文件的代码很多,但是核心逻辑就是引入了 compileToFunctions
方法, 扩展了 $mount
方法,支持将 options
的 template
转化为 render
函数。根据导入一直寻找,我们最终来到了 src/core/index.ts
import Vue from './instance/index' initGlobalAPI(Vue) // 初始化全局 Api
然后在 instance/index
文件
function Vue(options) { if (__DEV__ && !(this instanceof Vue)) { warn('Vue is a constructor and should be called with the `new` keyword') } this._init(options) } initMixin(Vue) stateMixin(Vue) eventsMixin(Vue) lifecycleMixin(Vue) renderMixin(Vue)
在这里我们知道, Vue
就是一个构造函数,只能通过 new Vue
进行实例化,然后通过不同函数对 prototype
进行扩展实现功能模块化,
四. 总结
Vue 的整体逻辑过于庞大,涉及到组件化, 响应式原理,编译等诸多逻辑。因此我会从不同的部分去阅读和解析源码。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论