Because I use VUE technology stack, recently also began to learn source code, in order to record personal understanding, if the text is wrong, please give advice.

1. The new Router and install

In vUE, we need to perform new router () first. After executing new router (), we should look at the constructor method defined by the VueRouter class.

constructor (options: RouterOptions = {}) { this.app = null this.apps = [] this.options = options this.beforeHooks = [] this.resolveHooks = []  this.afterHooks = [] this.matcher = createMatcher(options.routes || [], this)let mode = options.mode || 'hash'
    this.fallback = mode === 'history'&&! supportsPushState && options.fallback ! = =false
    if (this.fallback) {
      mode = 'hash'
    }
    if (!inBrowser) {
      mode = 'abstract'
    }
    this.mode = mode

    switch (mode) {
      case 'history':
        this.history = new HTML5History(this, options.base)
        break
      case 'hash':
        this.history = new HashHistory(this, options.base, this.fallback)
        break
      case 'abstract':
        this.history = new AbstractHistory(this, options.base)
        break
      default:
        if(process.env.NODE_ENV ! = ='production') {
          assert(false, `invalid mode: ${mode}`)}}}Copy the code

From the code we can see that the new mode determines which route to use and creates the matcher based on the options passed in.

Let’s see what happens when you execute the install method with vue.use() :

export function install (Vue) {
  if (install.installed && _Vue === Vue) return
  install.installed = true_Vue = Vue const isDef = v => v ! == undefined const registerInstance = (vm, callVal) => {let i = vm.$options._parentVnode
    if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {
      i(vm, callVal)
    }
  }

  Vue.mixin({
    beforeCreate () {
      if (isDef(this.$options.router)) {
        this._routerRoot = this
        this._router = this.$options.router
        this._router.init(this)
        Vue.util.defineReactive(this, '_route', this._router.history.current)
      } else {
        this._routerRoot = (this.$parent && this.$parent._routerRoot) || this
      }
      registerInstance(this, this)
    },
    destroyed () {
      registerInstance(this)
    }
  })

  Object.defineProperty(Vue.prototype, '$router', {
    get () { return this._routerRoot._router }
  })

  Object.defineProperty(Vue.prototype, '$route', {
    get () { return this._routerRoot._route }
  })

  Vue.component('RouterView', View)
  Vue.component('RouterLink', Link)

  const strats = Vue.config.optionMergeStrategies
  // use the same hook merging strategy for route hooks
  strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created
}
Copy the code

We added the $router and $route objects to the prototype link of Vue. This is why we can get these two objects from Vue when we use Vue. We also added the “beforeCreate” and “Destroyed” methods to each component. The router-view and router-link components are registered. Procedure

2. The matcher and the route

Let’s look at Matcher’s definition:

export typeMatcher = { match: (raw: RawLocation, current? : Route, redirectedFrom? : Location) => Route; addRoutes: (routes: Array<RouteConfig>) => void; };Copy the code

Matcher exposes the match method addRoutes, which is used to match routes and addRoutes to add route configurations.

The first generation of code in the creatMatcher() execution generates the pathList, pathMap, and nameMap objects, which are very important configurations for subsequent route matching.

  const { pathList, pathMap, nameMap } = createRouteMap(routes)
Copy the code

PathMap and nameMap respectively generate a mapping table with the path and name configured with route as the keys. The corresponding value is the RouteRecord instance.

Let’s look at the definition of RouteRecord:

declare typeRouteRecord = { path: string; regex: RouteRegExp; components: Dictionary<any>; instances: Dictionary<any>; name: ? string; parent: ? RouteRecord; redirect: ? RedirectOption; matchAs: ? string; beforeEnter: ? NavigationGuard; meta: any; props: boolean | Object | Function | Dictionary<boolean | Object | Function>; }Copy the code

Understand the meaning of each attribute against the actual data in the code:

key value
path The value of the path passed in
regex The regular match rules generated by path
components Path component
instances The route instance passed in when the route guard method is executed
name The name of the route
parent The parent of route is a recursive object that runs from the lowest level to the highest level
redirect Redirected path
matchAs Used to match aliases
props The parameters of the incoming route

Combined with the above explanation, we can get a general concept of how vue-Router works.

  1. Run new Router() to generate the routedRecord route configuration object

  2. Route matching Matches based on the regex of the route object

  3. Generate a Render Tree by recursively fetching the Component from the route parent object

  4. Execute the navigation guard method for each component

This article gives an overview of how vue-Router is executed, but there is no in-depth explanation of how router hops are executed. The next article will explain in detail how router hops are executed.