Vue源码解析(笔记)

github vue源码分析

认识flow

flow类型检查

安装flow

sudo npm install -g flow-bin

初始化flow

flow init

运行flow命令

命令: flow

在js文件中需要有需要有一下标志

/*@flow*/

例子 void

/*@flow*/

class Bar {
    x: string;           // x 是字符串
    y: string | number | void;  // y 可以是字符串或者数字
    z: boolean;

    constructor(x: string, y: string | number | void) {
        this.x = x
        this.y = y
        this.z = false
    }
}

var bar: Bar = new Bar('hello')

var obj: { a: string, b: number, c: Array<string>, d: Bar } = {
    a: 'hello',
    b: 11,
    c: ['hello', 'world'],
    d: new Bar('hello', 3)
}

Vue.js 源码目录设计

src
├── compiler        # 编译相关 
├── core            # 核心代码 
├── platforms       # 不同平台的支持
├── server          # 服务端渲染
├── sfc             # .vue 文件解析
├── shared          # 共享代码

Vue.js 源码构建

Vue.js 源码是基于Rollup 构建的,它的相关配置都在scripts目录下

构建脚本

通常一个基于NPM 托管的项目都会有一个package.json 文件,它的实际内容是JSON对象

我们通常会配置scripts字段作为NPM 执行脚本 Vue.js 源码构建脚本如下

{
"script":{
"build":"node scripts/build.js",
"build:ssr":"npm run build -- web-runtime-cjs,web-server-renderer",
"build:weex":" npm run build --weex"
 }
}

这里共有3条命令,作为都是构建Vue.js,后面2 条是在第一条命令的基础上,添加环境参数。

当在运行 npm run build 的时候 ,实际上就会执行 node scripts/build.js 接下来看看 它实际是怎么构建的

构建过程

我们对于构建过程分析是基于源码的,先打开构建的入口JS文件,在scripts/build.js 中

let builds = require('./config').getAllBuilds()
if(process.argv[2]){
 const filters = process.argv[2].split(',')
 builds = builds.filter(b => {
  return filters.some(f => b.oupput.file.indexOf(f)) > -f || b._name.indexOf(f) > -1
})
} else {
  builds = builds.filter(b => {
   return b.output.file.indexOf('weex') === -1
 })
}

build(builds)

这端代码逻辑非常简单。先从配置文件读取信息,在通过命令行参数对构建配置过滤,这样就可以构建出不同用途的Vue.js了。配置文件 在 scripts/config.js

const builds = {
'web-runtime-cjs': {
 entry: resolve('web/entry-runtime.js'),
 dest: resolve('dist/vue.runtime.common.js'),
 format:'cjs',
 banner
 },
 'web-full-cjs': {
  entry: resolve('web/entry-runtime-with-compilter.js'),
  dest:  resolve('dist/vue.common.js'),
  format: 'cjs',
  banner
 },
 'web-runtime-esm': {
  entry:resolve('web/entry-runtime.js'),
  dest: resolve('dist/vue.runtime.esm.js'),
  format:'es',
  banner
 },
 'web-full-esm': {
  entry: resolve('web/entry-runtime-with-compilter.js')
 }
}

这里列举了一些Vue.js 构建的配置 还有一些服务器渲染webpack 插件以及weex就不列举了

对于单个配置 它是遵循Rollop 的构建规则,其中entry 属性表示构建的入口JS文件地址,dess属性表示构建后的JS文件地址,fromat 属性表示构建的规则,cjs表示构建构建出来的文档遵循 CommonJS规范,es 表示构建出来的文件遵循ES Module 规范umd表示构建出来的文件遵循UMD规范

以web-runtime-cjs 配置为例 它的entryresolve('web/entry-runtime.js') 先看一下resolve 函数的定义

源码目录 scripts/config。js

const aliases = require('./alias')
const resolve = p => {
 const base = p.split('/')[0]
 if(aliases[base]) {
  return path.resolve(aliases[base], p.splice(base.length + 1))
 }else {
  return path.resolve(__dirname, '..', p)
  }
 }

这里resolve 函数实现非常简单,它先把resolve 函数传入的参数p通过/ 做了分割数组,然后取数组的第一个元素设置base 。在这个例子中参数pweb/entry-runtime.js ,那么base 则是webbase 并不是实际路径,它的真实路径借助了别名的配置,我们来看一下配置别名的代码,在scripts/alias 中

const path = require('path')

module.exports = {
 vue: path.resole(__dirname,'../src/platforms/web/entry-runtime-with-compiler'),
 compiler: path.resolve(__dirname,'../src/compiler'),
 core: path.resolve(__dirname,'../scr/core'),
 shared: path.resolve(__dirname,'../src/shared'),
 web: path.resolve(__dirname, '../src/platforms/web'),
 weex: path.resolve(__dirname, '../src/platforms/weex'),
 server: path.resolve(__dirname, '../src/server'),
 entries: path.resolve(__dirname, '../src/entries'),
 sfc:  path.resolve(__dirname, '../src/sfc')
}

很显然,这里web 对应的真实路径是path.resolve(__dirname,'../src/platforms/web'), 这个路径就找到了Vue.js源码的web目录,然后resolve 函数通过path.resolve(aliases[base], p.slice(base.length + 1)) 找到最终路径,它即使Vue.js源码目录下面的entry-runtime.js 。因此 web-runtime-cjs 配置对应的文件入口就找到了

它经过Rollup 的构建打包后,最终会在dist 目录先生成 vue.runtime.common.js

Runtime Only VS Runtime+ Compiler

通常我们利用vue-cli 去初始化我们的Vue.js 项目的时候会询问我们用 Runtime Only 版本还是Runtime+Compiler 版本,下面我们来对比这两个版本

  • Runtime Only

我们在使用Runtime Only 版本的Vue.js 的时候,通常需要借助webpack的vue-loader工具把.vue文件编译成 JavaScript , 因为在编译阶段做的,所以它只包运行时的Vue.js 代码, 因此代码体积更轻

  • Runtime+Compiler
    我们如果没有对代码进行预编译,但又使用了Vue的teplate 并传入了一个字符产,则需要在客户端编译模版 如下所示:
// 需要编译器的模版
new Vue({
 template:'<div>{{h1}}</div>'
})
// 这种情况不需要
new Vue({
 render (h) {
 return h('div',this.hi)
 }
})

因为在Vue.js 2.0 中最终渲染都是通过render 函数 ,如果写tempalte 属性, 则需要编译成render 函数,那么这个编译过程发生运行时,所以需要带有编译器的版本

很显然,这个编译过程对性能又一定损耗,所以通常我们更推荐 Runtime-Only 的Vue.js

zon

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue.js源码全方位深入解析最新下载地址.rar Vue.js源码全方位深入,帮你更深入了解vue 第1章 准备工作 介绍了 Flow、Vue.js 的源码目录设计、Vue.js 的源码构建方式,以及从入口开始分析了 Vue.js 的初始化过程。 第2章 数据驱动 详细讲解了模板数据到 DOM 渲染的过程,从 new Vue 开始,分析了 mount、render、update、patch 等流程。 第3章 组件化 分析了组件化的实现原理,并且分析了组件周边的原理实现,包括合并配置、生命周期、组件注册、异步组件。 第4章 深入响应式原理(上) 详细讲解了数据的变化如何驱动视图的变化,分析了响应式对象的创建,依赖收 集、派发更新的实现过程,一些特殊情况的处理,并对比了计算属性和侦听属性的实现,最后分析了组件更新的过程。 第5章 深入响应式原理(下) 详细讲解了数据的变化如何驱动视图的变化,分析了响应式对象的创建,依赖收集、派发更新的实现过程,一些特殊情况的处理,并对比了计算属性和侦听属性的实现,最后分析了组件更新的过程。 第6章 -编译(上) 从编译的入口函数开始,分析了编译的三个核心流程的实现:parse -> optimize -> codegen。 第7章 -编译(下) 从编译的入口函数开始,分析了编译的三个核心流程的实现:parse -> optimize -> codegen。 第8章 -扩展(上) 详细讲解了 event、v-model、slot、keep-alive、transition、transition-group 等常用功能的原理实现,该章节作为一个可扩展章节,未来会分析更多 Vue 提供的特性。 第9章 -扩展(中) 详细讲解了 event、v-model、slot、keep-alive、transition、transition-group 等常用功能的原理实现,该章节作为一个可扩展章节,未来会分析更多 Vue 提供的特性。 第10章 -扩展(下) 详细讲解了 event、v-model、slot、keep-alive、transition、transition-group 等常用功能的原理实现,该章节作为一个可扩展章节,未来会分析更多 Vue 提供的特性。 第11章 Vue-Router 分析了 Vue-Router 的实现原理,从路由注册开始,分析了路由对象、matcher,并深入分析了整个路径切换的实现过程和细节。 第12章 Vuex 分析了 Vuex 的实现原理,深入分析了它的初始化过程,常用 API 以及插件部分的实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值