Vue 源码学习 (1) - 起始篇

发布于 2023-12-09 15:29:09 字数 3392 浏览 27 评论 0

一. 写在前面

作为前端开发, Vue 是我日常工作中使用最多的框架,各种特性我都有进行了解。但是对于框架底层的原理却知之甚少,知道数据劫持,但是不知道依赖收集的具体过程。知道 diff 算法,但对 Vue 所做的算法优化不了解。一入门就学习了 Vue 的生命周期,却不了解组件实例化的整个过程。

总的来说就是似懂非懂,都知道一些,都不深入。因此学习源码,了解 Vue 的整体设计是我的主要目标。也希望通过 Vue 源码的学习能让我在工作中使用 Vue 更加的得心应手。

二. 基本介绍

Vue 的源码设计的东西太多了,我决定拆分成不同部分去阅读,带有目的去了解。

这里选择了当前(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 ,
也有支持 ESMesm , 也有兼容多格式的 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 方法,支持将 optionstemplate 转化为 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

信仰

暂无简介

文章
评论
26 人气
更多

推荐作者

櫻之舞

文章 0 评论 0

弥枳

文章 0 评论 0

m2429

文章 0 评论 0

野却迷人

文章 0 评论 0

我怀念的。

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文