I still don’t know enough about Vue – initglobal API

Time:2020-2-11

If you don’t say much, go to the source code first:

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 = <T>(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)
}

Part I:

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

It’s hijacked hereVueOfconfigProperty, making it impossible to modify.


Part II:

 Vue.util = {
    warn,
    extend,
    mergeOptions,
    defineReactive
  }
  • First lookwarn, it actually comes from/src/core/util/debug.js
 warn = (msg, vm) => {
    const trace = vm ? generateComponentTrace(vm) : ''

    if (config.warnHandler) {
      config.warnHandler.call(null, msg, vm, trace)
    } else if (hasConsole && (!config.silent)) {
      console.error(`[Vue warn]: ${msg}${trace}`)
    }
  }

  tip = (msg, vm) => {
    if (hasConsole && (!config.silent)) {
      console.warn(`[Vue tip]: ${msg}` + (
        vm ? generateComponentTrace(vm) : ''
      ))
    }
  }

If usedVueOfwarnHandlerIt should be known that this is a custom warning processing function. Haha, I haven’t used it, but I went to the official website to check it.
I still don't know enough about Vue - initglobal API

In fact, we can customizewarnHandlerFunction to collect project warnings. The same functionserrorHandler, if you need to go to the official documents.generateComponentTraceMethod will track the trace of the project warning component, which is a positioning function.

If not definedwarnHandlerIn the case of nonstandard writing components, errors will be printed on the console, which should be very common~

  • extendAlong the way from/share/utils
/**
 * Mix properties into target object.
 */
export function extend (to: Object, _from: ?Object): Object {
  for (const key in _from) {
    to[key] = _from[key]
  }
  return to
}

The function is to blend the properties of the source object into the target object.

  • mergeOptionsstay/core/util/options.jslower
export function mergeOptions (
  parent: Object,
  child: Object,
  vm?: Component
): Object {
  if (process.env.NODE_ENV !== 'production') {
    checkComponents(child)
  }

  if (typeof child === 'function') {
    child = child.options
  }

  normalizeProps(child, vm)
  normalizeInject(child, vm)
  normalizeDirectives(child)

  // Apply extends and mixins on the child options,
  // but only if it is a raw options object that isn't
  // the result of another mergeOptions call.
  // Only merged options has the _base property.
  if (!child._base) {
    if (child.extends) {
      parent = mergeOptions(parent, child.extends, vm)
    }
    if (child.mixins) {
      for (let i = 0, l = child.mixins.length; i < l; i++) {
        parent = mergeOptions(parent, child.mixins[i], vm)
      }
    }
  }

  const options = {}
  let key
  for (key in parent) {
    mergeField(key)
  }
  for (key in child) {
    if (!hasOwn(parent, key)) {
      mergeField(key)
    }
  }
  function mergeField (key) {
    const strat = strats[key] || defaultStrat
    options[key] = strat(parent[key], child[key], vm, key)
  }
  return options
}

The role is to merge parent-child policy items into one
checkComponentsIs to check the component, which traverses the incomingchildOfcomponentsProperty to check whether the component name is canonical.
normalizePropsIts function is to unifyprops: [?]andprops: {?}Form into the latter.
normalizeInjectIt was also introduced by unified standardizationinjectinjectIt’s usually a parent component or a grandparent componentprovideIs also a way of communication.
normalizeDirectivesStandardize custom instructions, if the passed in is afunction, will be defined as{ bind: function, update: function}This form.
Next, if the subcomponent hasextendsperhapsmixinsFunctions such as the parent component will be changed, and will be analyzed when encountering specific calls.
mergeFieldThis is the actual thing, it will followstratsThe policies defined are merged.

strats.el = strats.propsData = function (parent, child, vm, key) {
strats.data = function () {...}
strats.props = ...
strats.methods = ...
strats.computed = ...
strats.watch = ...
...
  • defineReactivestay/core/observer/index.jsNext, isVueThe key to implementing responsive will be discussed in detail later. Here is equivalent toutilThis function is given.
  • setanddelThe function is to add or delete attributes in response
  • nextTickNext timeDOMA delayed callback is performed after the update cycle ends. AndJSThe event running mechanism of is very similar, and an article will be recorded separately.
  • Vue.observableThis isVue 2.6Version of the new API, it is obvious that it uses theVueOfObserveIts purpose is, if a small project doesn’t work at allVuexFor state management, you can use it to customize a small responsivestoreFor global use, please refer to official documents for details.
  • Vue.options
//Iterated through the initialization of vue.options by asset types
  Vue.options = Object.create(null)
  ASSET_TYPES.forEach(type => {
    Vue.options[type + 's'] = Object.create(null)
  })
//The following is the definition of asset types
  export const ASSET_TYPES = [
    'component',
    'directive',
    'filter'
  ]
  • extend(Vue.options.components, builtInComponents)takebuiltInCompoentsAttribute blendingVue.options.components, there are somekeep-aliveSomething related.
  • initUse(Vue)As follows:
export function initUse (Vue: GlobalAPI) {
  Vue.use = function (plugin: Function | Object) {
    const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
    if (installedPlugins.indexOf(plugin) > -1) {
      return this
    }

    // additional parameters
    const args = toArray(arguments, 1)
    args.unshift(this)
    if (typeof plugin.install === 'function') {
      plugin.install.apply(plugin, args)
    } else if (typeof plugin === 'function') {
      plugin.apply(null, args)
    }
    installedPlugins.push(plugin)
    return this
  }
}

toVueAddeduse, receive a plug-in parameter, and install the plug-in. We usually register similarrouterWhen waiting for plug-ins, they will useVue.use(router)。 It maintains a_installedPluginsArray is used to store all installed plug-ins. During installation, it will determine whether the plug-ins have been implementedinstallMethod, if any, the plug-in will executeinstallMethod, hereVueSkillfully infuse oneself intoinstallIn the parameters of the method, the advantage is that in the implementationinstallNo wayimport VueNow.

  • initMixin
export function initMixin (Vue: GlobalAPI) {
  Vue.mixin = function (mixin: Object) {
    this.options = mergeOptions(this.options, mixin)
    return this
  }
}

Global blendingmixinMerge policy into globaloptions, once the global blending is used, because the component is registered locally, it is actually calledVue.extendMethod, which is also calledmergeOptions, so it will affect each later createdVueExample. It should be used properly.

  • initExtend
export function initExtend (Vue: GlobalAPI) {
  /**
   * Each instance constructor, including Vue, has a unique
   * cid. This enables us to create wrapped "child
   * constructors" for prototypal inheritance and cache them.
   */
  Vue.cid = 0
  let cid = 1

  /**
   * Class inheritance
   */
  Vue.extend = function (extendOptions: Object): Function {
    extendOptions = extendOptions || {}
    const Super = this
    const SuperId = Super.cid
    const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})
    if (cachedCtors[SuperId]) {
      return cachedCtors[SuperId]
    }

    const name = extendOptions.name || Super.options.name
    if (process.env.NODE_ENV !== 'production' && name) {
      validateComponentName(name)
    }

    const Sub = function VueComponent (options) {
      this._init(options)
    }
    Sub.prototype = Object.create(Super.prototype)
    Sub.prototype.constructor = Sub
    Sub.cid = cid++
    Sub.options = mergeOptions(
      Super.options,
      extendOptions
    )
    Sub['super'] = Super

    // For props and computed properties, we define the proxy getters on
    // the Vue instances at extension time, on the extended prototype. This
    // avoids Object.defineProperty calls for each instance created.
    if (Sub.options.props) {
      initProps(Sub)
    }
    if (Sub.options.computed) {
      initComputed(Sub)
    }

    // allow further extension/mixin/plugin usage
    Sub.extend = Super.extend
    Sub.mixin = Super.mixin
    Sub.use = Super.use

    // create asset registers, so extended classes
    // can have their private assets too.
    ASSET_TYPES.forEach(function (type) {
      Sub[type] = Super[type]
    })
    // enable recursive self-lookup
    if (name) {
      Sub.options.components[name] = Sub
    }

    // keep a reference to the super options at extension time.
    // later at instantiation we can check if Super's options have
    // been updated.
    Sub.superOptions = Super.options
    Sub.extendOptions = extendOptions
    Sub.sealedOptions = extend({}, Sub.options)

    // cache constructor
    cachedCtors[SuperId] = Sub
    return Sub
  }
}

Here’s ajs, which is used to createVueSubclass constructor for. Here you can verify the above, which willSuper.optionsandextendOptionsAmalgamation.

  • initAssetRegisters
export function initAssetRegisters (Vue: GlobalAPI) {
  /**
   * Create asset registration methods.
   */
  ASSET_TYPES.forEach(type => {
    Vue[type] = function (
      id: string,
      definition: Function | Object
    ): Function | Object | void {
      if (!definition) {
        return this.options[type + 's'][id]
      } else {
        /* istanbul ignore if */
        if (process.env.NODE_ENV !== 'production' && type === 'component') {
          validateComponentName(id)
        }
        if (type === 'component' && isPlainObject(definition)) {
          definition.name = definition.name || id
          definition = this.options._base.extend(definition)
        }
        if (type === 'directive' && typeof definition === 'function') {
          definition = { bind: definition, update: definition }
        }
        this.options[type + 's'][id] = definition
        return definition
      }
    }
  })
}

ASSET_TYPESAs mentioned above, initializationVueFor example, when we want to register a build, we will callVue.component, which is used when the instruction is to be customizedVue.directive, which is defined here.

summary

This is mainly aboutVueOfficial websiteAPIIt’s not particularly detailed, but it’s also introduced one by one. If you want to pursue a deeper understanding, you can go togitDownload a source code, in fact, in the inheritance there, similar toinitPropsinitComputedIt can also improve the quality of the projectVueUnderstanding of usage.