欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

实例讲解vue源码架构

程序员文章站 2022-05-25 21:53:39
下载 去github上下载vue npm install npm run dev 运行起来 rollup + flow vue使用使用rollu...

下载

去github上下载vue

npm install 
npm run dev

运行起来

rollup + flow

vue使用使用rollup打包,flow规范数据类型

rollup可以先用webpack套用,读起来差不多,时间有限,毕竟只有5分钟,这个就不用去看rollup文档了

入口

打开package.json

我们看scripts配置

"dev": "rollup -w -c scripts/config.js --environment target:web-full-dev",
 "dev:cjs": "rollup -w -c scripts/config.js --environment target:web-runtime-cjs-dev",

找到scripts/config.js

打开

根据配置target的不同会选择不同的config

同时在这里配置了process.env.node_env 环境

target有commonjs,es modules,umd关于js引入类型的

还有weex,ssr

'web-runtime-cjs-dev': {
  entry: resolve('web/entry-runtime.js'),
  dest: resolve('dist/vue.runtime.common.dev.js'),
  format: 'cjs',
  env: 'development',
  banner
 }

在alias.js下设置了别名路径

我们先介绍src/platforms

里面有web和weex 分别的web和weex入口

在web文件下是commonjs,es modules,umd关于js引入类型,server的打包入口

打开web/entry-runtime.js

引入

import vue from './runtime/index'
export default vue

打开./runtime/index

import vue from 'core/index'
 
vue.prototype.$mount = function (
 el?: string | element,
 hydrating?: boolean
): component {
 el = el && inbrowser ? query(el) : undefined
 return mountcomponent(this, el, hydrating)
}
export default vue

在vue原型上添加了mount方法

处理了devtools,没有安装提醒安装devtools

给了这句提示dev环境提示

you are running vue in development mode.
make sure to turn on production mode when deploying for production.
see more tips at https://vuejs.org/guide/deployment.html

platforms目录夹讲解完毕

core目录

打开core/instance/index

映入眼前的是

function vue (options) {
 if (process.env.node_env !== 'production' &&
  !(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)
 
export default vue

先执行的是initmixin(vue)

打开init

export function initmixin (vue) {
 vue.prototype._init = function (options?: object) {
  const vm = this
  // a uid 
  vm._uid = uid++
   
  let starttag, endtag
  /* istanbul ignore if */
  if (process.env.node_env !== 'production' && config.performance && mark) {
   starttag = `vue-perf-start:${vm._uid}`
   endtag = `vue-perf-end:${vm._uid}`
   mark(starttag)
  }
 
  // a flag to avoid this being observed
  vm._isvue = true
  // 处理传入的options
  // merge options
  if (options && options._iscomponent) {
   // optimize internal component instantiation
   // since dynamic options merging is pretty slow, and none of the
   // internal component options needs special treatment.
   initinternalcomponent(vm, options)
  } else {
    // 传入的options,默认的options一起合并挂载到vm.$options上
   vm.$options = mergeoptions(
    resolveconstructoroptions(vm.constructor),
    options || {},
    vm
   )
  }
  /* istanbul ignore else */
  if (process.env.node_env !== 'production') {
   // 代理
   initproxy(vm)
  } else {
   vm._renderproxy = vm
  }
  // 生命周期
  initlifecycle(vm)
   // emit on 事件
  initevents(vm)
  // 处理render vdom
  initrender(vm)
  callhook(vm, 'beforecreate')
  // 处理injections
  initinjections(vm) // resolve injections before data/props
  // 双向数据绑定,监听订阅
  initstate(vm)
  initprovide(vm) // resolve provide after data/props
  callhook(vm, 'created')
   
  /* istanbul ignore if */
  if (process.env.node_env !== 'production' && config.performance && mark) {
   vm._name = formatcomponentname(vm, false)
   mark(endtag)
   measure(`vue ${vm._name} init`, starttag, endtag)
  }
  // 渲染到dom
  if (vm.$options.el) {
   vm.$mount(vm.$options.el)
  }
 }
}

lifecycle

打开 lifecycle

export function callhook (vm: component, hook: string) {
 // disable dep collection when invoking lifecycle hooks
 pushtarget()
 //执行对象的周期函数,周期函数最后被处理成数组
 const handlers = vm.$options[hook]
 const info = `${hook} hook`
 if (handlers) {
  for (let i = 0, j = handlers.length; i < j; i++) {
   invokewitherrorhandling(handlers[i], vm, null, vm, info)
  }
 }
 if (vm._hashookevent) {
  vm.$emit('hook:' + hook)
 }
 poptarget()

callhook 的时候,是执行相应周期,开发者在周期函数里所写的

events

initevents实现了 emit on 等方法,请参考监听者订阅者模式,这里不详解

render
rendermixin函数
添加了 $nexttick _render 原型对象

$nexttick会在dom跟新后立即调用

nexttick(fn, this)是一个自执行函数

_render返回的是node的js数据,还不是dom

做了vdom

initrender函数
给vm添加了_c和 $createelement用来渲染的方法

state

if (!(key in vm)) {
   proxy(vm, `_props`, key)
  }

给vue属性做代理,访问this.a可以得到this.data.a 的值

export function initstate (vm: component) {
 vm._watchers = []
 const opts = vm.$options
 if (opts.props) initprops(vm, opts.props)
 if (opts.methods) initmethods(vm, opts.methods)
 if (opts.data) {
  initdata(vm)
 } else {
  observe(vm._data = {}, true /* asrootdata */)
 }
 if (opts.computed) initcomputed(vm, opts.computed)
 if (opts.watch && opts.watch !== nativewatch) {
  initwatch(vm, opts.watch)
 }
}

给数据做监听

statemixin函数

添加原型对象

vue.prototype.$set = set
vue.prototype.$delete = del

其他

src/compiler 做了编译处理

core/componetd 做了keep-alive

core/util 封装了通用方法

core/vdom vdom算法

以上整体架构分析完毕

实例讲解vue源码架构