vue的源码学习之四——1.入口文件

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qishuixian/article/details/84957041
  • 介绍

        版本:2.5.17

  • 从package.json文件开始

    根目录下的package.json文件。在 web 应用下,我们来分析 Runtime + Compiler 构建出来的 Vue.js,它的入口是 src/platforms/web/entry-runtime-with-compiler.js,因此这里我们只看第一个,也就是npm run dev所执行的命令。

     

    •  npm run dev

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

     

    • scripts/config.js

它会根据传入参数的不同,而根据不同版本的Vue.js形成构建工具rollup的不同配置 。config.js文章介绍请看(vue的源码学习之三——源码构建

const builds = {
  ...
  ...
  ...
  // Runtime+compiler development build (Browser)
  'web-full-dev': {
    entry: resolve('web/entry-runtime-with-compiler.js'),
    dest: resolve('dist/vue.js'),
    format: 'umd',
    env: 'development',
    alias: { he: './entity-decoder' },
    banner
  },
  ...
  ...
  ...
}

function genConfig (opts) {
  ...
}

if (process.env.TARGET) {
  module.exports = genConfig(builds[process.env.TARGET])
} else {
  exports.getBuild = name => genConfig(builds[name])
  exports.getAllBuilds = () => Object.keys(builds).map(name => genConfig(builds[name]))
}

     我们看到它调用了getConfig(builds[process.env.TARGET]),getConfig用于生成rollup的配置文件。builds是一个对象,获取它的process.env.TARGET值,在package.json中,我们看到dev中有TARGET:web-full-dev参数。 
根据web-full-dev这个参数,我们到找到该版本的Vue.js的相关配置,配合alias.js这样入口文件我们就找到了,也就是/src/platforms/web/entry-runtime-with-compiler.js。

  • 入口文件

    • 寻找Vue对象的所在

         入口文件:/src/platforms/web/entry-runtime-with-compiler.js。 
         在文件中我们看到:

    import Vue from './runtime/index'

        src/platforms/web/runtime/index.js:

    import Vue from 'core/index'

         src/core/index.js:

    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)
    }
    //
    // 每个Mixin就是往vue定的原型方法 Vue.prototype.xx = yy 用function方便代码的管理,组装,添加原型方法各个文件各个模板,用class,需要一个主文件,添加主属性等。所以vue使用function
    initMixin(Vue)
    stateMixin(Vue)
    eventsMixin(Vue)
    lifecycleMixin(Vue)
    renderMixin(Vue)
    
    export default Vue
    
    import Vue from './instance/index'

       src/core/instance/index.js:

    扫描二维码关注公众号,回复: 4810642 查看本文章

       至此我们找到了Vue对象的所在。

    • 分析Vue对象

     在src/core/instance/index.js中我们找到了定义Vue对象的所在之处。它的构造函数及其简单:

    
    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)
    }
    
    

     首先判断如果是不是生产环境,且不是通过new关键字来创建对象的话,就在控制台打印一个warning,之后调用了this._init(options)函数。 
    下面的几个函数,分别在Vue.prototype原型上绑定了一些实例方法,Vue的实例方法

    // _init
    initMixin(Vue)  
    // $set、$delete、$watch
    stateMixin(Vue)
    // $on、$once、$off、$emit
    eventsMixin(Vue)
    // _update、$forceUpdate、$destroy
    lifecycleMixin(Vue)
    // $nextTick、_render、以及多个内部调用的方法
    renderMixin(Vue)

    我们终于看到了 Vue 的庐山真面目,它实际上就是一个用 Function 实现的类,我们只能通过 new Vue 去实例化它。

    为何 Vue 不用 ES6 的 Class 去实现呢?我们往后看这里有很多 xxxMixin 的函数调用,并把 Vue 当参数传入,它们的功能都是给 Vue 的 prototype 上扩展一些方法,Vue 按功能把这些扩展分散到多个模块中去实现,而不是在一个模块里实现所有,这种方式是用 Class 难以实现的。这么做的好处是非常方便代码的维护和管理,这种编程技巧也非常值得我们去学习。

    • initGlobalAPI

      我们按照刚才所提到的文件引入顺序一步步来看。src/core/instance/index.js执行之后,是src/core/index.js文件 

    import { initGlobalAPI } from './global-api/index'
    import { isServerRendering } from 'core/util/env'
    import { FunctionalRenderContext } from 'core/vdom/create-functional-component'
    
    // 全局方法
    initGlobalAPI(Vue)
    
    Object.defineProperty(Vue.prototype, '$isServer', {
      get: isServerRendering
    })
    
    Object.defineProperty(Vue.prototype, '$ssrContext', {
      get () {
        /* istanbul ignore next */
        return this.$vnode && this.$vnode.ssrContext
      }
    })
    
    // expose FunctionalRenderContext for ssr runtime helper installation
    Object.defineProperty(Vue, 'FunctionalRenderContext', {
      value: FunctionalRenderContext
    })
    
    Vue.version = '__VERSION__'
    
    export default Vue

    该文件首先调用了initGlobalAPI,引自src/core/global-api/index.js。 

    • 扩展全局的静态方法

         src/core/global-api/index.js中定义了给 Vue 这个对象本身扩展全局的静态方法 

/* @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 {
  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

  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 官网中关于全局 API 都可以在这里找到,这里不会介绍细节,会在之后的章节我们具体介绍到某个 API 的时候会详细介绍。有一点要注意的是,Vue.util 暴露的方法最好不要依赖,因为它可能经常会发生变化,是不稳定的

  • 总结

  1. 我们找到了vue构造函数,并知道了向vue原型中添加了很多实例方法
  2. 知道了通过 initGlobalAPI 向vue中添加了很多的静态方法

学习文档:https://ustbhuangyi.github.io/vue-analysis/components/lifecycle.html 

猜你喜欢

转载自blog.csdn.net/qishuixian/article/details/84957041