vue-router源码解读之插件注册

43 阅读2分钟

文件入口

  1. 打开package.json,发现文件入口是"build": "node build/build.js",

  2. 找到build文件夹,发现加载的主要是config文件夹中的内容

  3. 找到config文件,发现导出了一个数组,但是导出的并不是看到的数组,而是修改了的config数组对象

function genConfig(opts) {
  const config = {
    input: {
      // 文件入口
      input: opts.input || resolve('src/index.js'),
      // 插件配置
      plugins: [
        flow(),
        node(),
        cjs(),
        replace({
          __VERSION__: version
        })
      ],
      external: ['vue']
    },
    // 输出信息
    output: {
      file: opts.file,
      format: opts.format,
      banner,
      name: 'VueRouter'
    }
  }

  if (opts.env) {
    config.input.plugins.unshift(
      replace({
        'process.env.NODE_ENV': JSON.stringify(opts.env)
      })
    )
  }

  if (opts.transpile !== false) {
    config.input.plugins.push(buble())
  }
  // 最终的输出
  return config
}

插件注册

根据index入口文件,找到 vueRouter 类

export default class VueRouter {
  static install: () => void
  ...
  ...
}

我们看到vueRouter的第一个方法就是install函数,我们知道vue的插件基本都是需要install函数,才能使用vue.use注册。

原因如下,来到vue的源码

export function initUse(Vue: GlobalAPI) {
  // vue.use是一个函数,里面传入一个plugin,可以是函数或者别的什么
  Vue.use = function (plugin: Function | any) {
    // 首先判断 是否已经有 plugin注册在vue上了,如果有就跳过,没有就初始化
    const installedPlugins =
      this._installedPlugins || (this._installedPlugins = [])
    // 再次判断 当前函数 是否在 vue中注册过,如果注册了就直接返回,避免重复注册
    if (installedPlugins.indexOf(plugin) > -1) {
      return this
    }
    // additional parameters use函数可能会接收到不止一个参数,取出除第一个参数之外的参数
    const args = toArray(arguments, 1)
    // 把vue排到第一位
    args.unshift(this)
    // 如果plugin有install函数,就执行install函数
    if (isFunction(plugin.install)) {
      plugin.install.apply(plugin, args)
      // 插件本身就是个install函数
    } else if (isFunction(plugin)) {
      plugin.apply(null, args)
    }
    // 将plugin推入到installedPlugins
    installedPlugins.push(plugin)
    // 返回vue
    return this
  }
}

所以我们的vue-router中也必须包含install函数,才能注册到vue中

VueRouter的注册

VueRouter.install = install

转到install.js,看看在vue初始化之前都做了什么

    beforeCreate() {
      // options 获取Vue实例的自定义属性
      // 在vue-router实例化时会将 router挂载到 vue的options里面
      if (isDef(this.$options.router)) {
        // 只有存在router,才会在vue上添加下面的属性
        this._routerRoot = this
        this._router = this.$options.router
        this._router.init(this)
        Vue.util.defineReactive(this, '_route', this._router.history.current)
      } else {
        // 只有根实例才有 _routerRoot 属性,
        // 因此如果当前实例不是根实例,那么它的父组件可能是根实例,
        // 可以通过 this.$parent._routerRoot 访问到根实例的 _routerRoot 属性,
        // 并将其赋值给当前实例的 _routerRoot 属性。如果当前实例的父组件也不是根实例,则会递归向上查找,直到找到根实例为止。
        this._routerRoot = (this.$parent && this.$parent._routerRoot) || this
      }
      // 将实例注册到父级组件
      registerInstance(this, this)
    },

总结:如果想要在vue中注册我们的路由,首先需要的就是一个install函数,接收vue的功能,然后把自身的实例挂载到vue上。