Vue初始化源码解析

本文主要来描述下Vue的整体创建流程,可以熟悉下Vue的初始化的过程,帮助大家明白当我们在运行new Vue()的时候发生了什么。

首先来看下Vue初始时的方法:

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

从代码中可以看到new Vue时会将调用_init方法,同时将一些方法、变量等挂载到Vue或则其原型上,具体如下:

  • initMixin(Vue):定义_init方法,初始化一些需要的变量,如$refs、_watch等
  • stateMixin(Vue):定义数据相关的方法 s e t , set, set,delete, w a t c h 方 法 , 挂 载 watch方法,挂载 watchdata、$props等
  • eventsMixin(Vue):定义事件相关的方法 o n , on, ononce, o f f , off, offemit
  • lifecycleMixin(Vue):定义_update,及生命周期相关的 f o r c e U p d a t e 和 forceUpdate和 forceUpdatedestroy
  • renderMixin(Vue):定义$nextTick,_render来转化得到虚拟节点

之后,开始挂载一些全局方法到Vue上,如下:

import Vue from './instance/index'
import { initGlobalAPI } from './global-api/index'
import { isServerRendering } from 'core/util/env'
import { FunctionalRenderContext } from 'core/vdom/create-functional-component'

initGlobalAPI(Vue)

看下global部分:

/* @flow */

import config from '../config'
import { initUse } from './use'
import { initMixin } from './mixin'
import { initExtend } from './extend'
import { initAssetRegisters } from './assets'
import { set, del } from '../observer/index'
import { ASSET_TYPES } from 'shared/constants'
import builtInComponents from '../components/index'
import { observe } from 'core/observer/index'

import {
  warn,
  extend,
  nextTick,
  mergeOptions,
  defineReactive
} from '../util/index'

export function initGlobalAPI (Vue: GlobalAPI) {
  // config
  const configDef = {}
  configDef.get = () => config
  if (process.env.NODE_ENV !== 'production') {
    configDef.set = () => {
      warn(
        'Do not replace the Vue.config object, set individual fields instead.'
      )
    }
  }
  Object.defineProperty(Vue, 'config', configDef)

  // exposed util methods.
  // NOTE: these are not considered part of the public API - avoid relying on
  // them unless you are aware of the risk.
  Vue.util = {
    warn,
    extend,
    mergeOptions,
    defineReactive
  }

  Vue.set = set
  Vue.delete = del
  Vue.nextTick = nextTick

  // 2.6 explicit observable API
  Vue.observable = (obj: T): T => {
    observe(obj)
    return obj
  }

  Vue.options = Object.create(null)
  ASSET_TYPES.forEach(type => {
    Vue.options[type + 's'] = Object.create(null)
  })

  // this is used to identify the "base" constructor to extend all plain-object
  // components with in Weex's multi-instance scenarios.
  Vue.options._base = Vue

  extend(Vue.options.components, builtInComponents)

  initUse(Vue)
  initMixin(Vue)
  initExtend(Vue)
  initAssetRegisters(Vue)
}

定义了各种全局方法绑定到Vue上,因此只需要初始化新建Vue对象,就开始执行上述操作,直接得到一个功能丰富的Vue对象

目录结构:

|-- dist  打包后的vue版本
|-- src  未编译代码(源码)
    |-- compiler  编译器,将template模板编译为render函数
    |-- core  不区分平台的核心代码
        |-- components  通用的抽象组件
        |-- global-api  全局API
        |-- instance  实例的构造函数和原型方法
        |-- observer  vue检测数据数据变化改变视图的代码实现
        |-- util  常用的工具方法
        |-- vdom  将render函数转为vnode从而patch为真实dom以及diff算法的代码实现
    |-- platforms  针对web平台和weex平台分别的实现,并提供统一的API供调用
    |-- server  服务端渲染
    |-- sfc  .vue单文件组件解析
    |-- shared  全局通用工具方法

最后再来分析下dist文件夹,虽然看到源码库里面有多达N个版本,接下来来分析下:

vue.common.js
vue.esm.js
vue.js
vue.min.js
vue.runtime.common.js
vue.runtime.esm.js
vue.runtime.js
vue.runtime.min.js

按照构建方式分, 可以分成 完整构建(包含独立构建和运行时构建) 和 运行时构建
按照规范分, 可以分成 UMD, CommonJS 和 ES Module

简单来说, 完整构建 和 运行时构建的区别就是, 可不可以用template选项, 和文件大一点,小一点。

  • vue.common.js

属于: 基于 CommonJS 的完整构建
可以用于 Webpack-1 和 Browserify 之类打包工具
因为是完整构建, 所以可以使用template选项, 如:

import Vue from 'vue'
new Vue({
  template: `
    

Basic

` }).$mount('#app')

注意: 用 webpack-1 之类打包工具时, 使用该版本, 需要配置别名, 以 webpack 为例:

{
  resolve: {
    alias: {
      'vue$': 'vue/dist/vue.common.js'
    }
  }
}
  • vue.esm.js

属于: 基于 ES Module 的完整构建
可以用于 Webpack-2 和 rollup 之类打包工具,因为是完整构建, 所以可以使用template选项, 如:

import Vue from 'vue'
new Vue({
  template: `
    

Basic

` }).$mount('#app')

注意: 用 webpack-2 之类打包工具时, 使用该版本, 需要配置别名, 以 webpack 为例:

{
  resolve: {
    alias: {
      'vue$': 'vue.esm.js'
    }
  }
}
  • vue.js

属于: 基于 UMD 的完整构建
可以用于直接 CDN 引用
因为是完整构建, 所以可以使用template选项, 如:



  • vue.min.js

和 vue.js 一样, 属于压缩后版本

  • vue.runtime.common.js

属于: 基于 CommonJS 的运行时构建
可以用于 Webpack-1 和 Browserify 之类打包工具
运行时构建不包含模板编译器,因此不支持template选项,只能用render选项,但即使使用运行时构建,在单文件组件中也依然可以写模板,因为单文件组件的模板会在构建时预编译为render函数, render函数的使用, 请参考: http://cn.vuejs.org/v2/guide/render-function.html

import Vue from 'vue'
new Vue({
  render: function(h){
    return h('h1', 'Hi Vue')
  }
}).$mount('#app')
  • vue.runtime.esm.js

属于: 基于 ES Module 的运行时构建
可以用于 Webpack-2 和 rollup 之类打包工具
运行时构建不包含模板编译器,因此不支持template选项,只能用render选项,但即使使用运行时构建,在单文件组件中也依然可以写模板,因为单文件组件的模板会在构建时预编译为render函数, render函数的使用, 请参考: http://cn.vuejs.org/v2/guide/render-function.html

import Vue from 'vue'
new Vue({
  render: function(h){
    return h('h1', 'Hi Vue')
  }
}).$mount('#app')
  • vue.runtime.js

属于: 基于 UMD 的运行时构建
可以用于直接 CDN 引用
该版本和vue.js类似, 可以用于直接 CDN 引用, 因为不包含编译器, 所以不能使用template选项, 只能使用render函数



  • vue.runtime.min.js
    和 vue.runtime.js 一样, 属于压缩后版本

你可能感兴趣的:(vuejs,源码,js,javascript,webpack,vue.js,es6,typescript)