前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Vue2.5源码阅读笔记01—代码结构与初始化

Vue2.5源码阅读笔记01—代码结构与初始化

原创
作者头像
CS逍遥剑仙
修改2018-09-11 11:54:56
1.2K0
修改2018-09-11 11:54:56
举报
文章被收录于专栏:禅林阆苑

Vue2.5源码阅读笔记01—代码结构与初始化

Write By CS逍遥剑仙

我的主页: www.csxiaoyao.com

GitHub: github.com/csxiaoyaojianxian

Email: sunjianfeng@csxiaoyao.com

QQ: 1724338257

1. 前言

Vue作为当下最流行的渐进式的js框架,其渐进式的思想、虚拟DOM的运用、组件化的开发模式、响应式数据侦听原理值得开发者进行探索学习,其中运用的代码组织的技巧,对平时的开发大有裨益。本系列笔记初步分为8个章节,记录本人源码的阅读过程。

2. 构建准备

2.1 Flow静态类型检查

虽然Vue源码打包压缩后只有20kb,足够小巧轻量,但是源码还是相对复杂,开发者为了增强源码的可读性和可维护性,在ES2015和ESLint基础上,引入Flow做静态类型检查。Flow和TypeScript极为相似,前者由Facebook出品,后者则是微软的杰作。

Flow的类型检查分2种方式:

  • 类型推断:通过变量的使用上下文推断变量类型并检查,不需要添加任何代码进行改造
  • 类型注释:通过代码中开发者写的类型注释检查,需要开发者写明类型注释

具体的语法和细节可以阅读官方文档:flow.org

2.2 Rollup构建工具

Vue.js 源码是基于 Rollup 构建的,Rollup和webpack类似,但是Rollup相比webpack更加轻量,没有对图片等文件的打包处理,适合js框架的打包,构建相关配置在scripts目录下。最终的打包版本分为 Runtime OnlyRuntime + Compiler,显然Runtime Only版本会更加轻量,需要webpack在开发环境对vue文件预编译为js文件,由于前端浏览器进行template编译会消耗大量性能,因此开发更加推荐Runtime Only方式,此处学习过程参考的是 Runtime + Compiler

3. 目录结构

Vue.js 的源码存放在 src 目录下,整个目录结构十分清晰,目录结构如下所示:

代码语言:txt
复制
src
├── compiler    # 编译
├── core        # 核心代码
├── platforms   # 平台支持,web & weex
├── server      # 服务端渲染
├── sfc         # vue文件解析
├── shared      # 共享代码

4. 从入口文件寻找Vue定义

从配置文件夹script下的config.js可以看到,入口文件为平台目录下的 src/platforms/web/entry-runtime.js,在入口文件中能够找到引用了 src/core/index.js 下的Vue,最终确定Vue的定义在 src/core/instance/index.js

代码语言:txt
复制
'web-runtime-cjs': {
    entry: resolve('web/entry-runtime.js'),
    dest: resolve('dist/vue.runtime.common.js'),
    format: 'cjs',
    banner
}

Vue的定义非常清晰,Vue是一个 Function 类,只能通过 new Vue 实例化。Vue的定义下面有多个Mixin方法,可以给 Vue 的 prototype 扩展方法,这种开发技巧能够使得代码结构更加清晰、易于维护,但这种方式ES6的Class难以实现,因此此处使用的是ES5的Funtion构建类

代码语言:txt
复制
import { initMixin } from './init'
import { stateMixin } from './state'
import { renderMixin } from './render'
import { eventsMixin } from './events'
import { lifecycleMixin } from './lifecycle'
import { warn } from '../util/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

5. new Vue 实例化

Vue类使用 Function 实现,只能通过 new 关键字初始化,在上面的Vue定义中可以看到,Vue的初始化主要是通过 this._init 方法,传入options参数,_init方法在 src/core/instance/init.js 中定义。Vue 初始化进行了合并配置、初始化生命周期、初始化事件、初始化渲染、初始化 data/props/computed/watcher 等,都是通过调用函数执行,这些函数分别封装在不同的js文件中。初始化最后,检测到如果有 el 属性,则调用 vm.$mount 方法挂载 vm,即把模板渲染成最终的 DOM。

代码语言:txt
复制
export function initMixin (Vue: Class<Component>) {
  Vue.prototype._init = function (options?: Object) {
    const vm: Component = 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
    // 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 {
      vm.$options = mergeOptions(
        resolveConstructorOptions(vm.constructor),
        options || {},
        vm
      )
    }
    /* istanbul ignore else */
    if (process.env.NODE_ENV !== 'production') {
      initProxy(vm)
    } else {
      vm._renderProxy = vm
    }
    // expose real self
    vm._self = vm
    initLifecycle(vm)
    initEvents(vm)
    initRender(vm)
    callHook(vm, 'beforeCreate')
    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)
    }

    if (vm.$options.el) {
      vm.$mount(vm.$options.el)
    }
  }
}
www.csxiaoyao.com
www.csxiaoyao.com

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Vue2.5源码阅读笔记01—代码结构与初始化
    • 1. 前言
      • 2. 构建准备
        • 2.1 Flow静态类型检查
        • 2.2 Rollup构建工具
      • 3. 目录结构
        • 4. 从入口文件寻找Vue定义
          • 5. new Vue 实例化
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档