“This is the 12th day of my participation in the First Challenge 2022. For details: First Challenge 2022.”

Antecedents feed

From the previous article, how does vue-Router find vUE components to render? Vue -router Matcher: Route is processed when the vue-router finds a vue component to render. RouteRecordNormalized routing records

This article describes how Matcher handles the alias part of route, the redirection and alias of vue-Router documents

Note: The matcher analysis and source code in this article correspond to vuE-Router4, which is vuE3 version of the router

{route: “/”, Redirect: “/test”} {route: {path: “/”, Redirect: “/test”}[route,route,...]

The alias processing

Refer to the vue-router document-alias documentation for an introduction to the alias handling API

Anyway, this is what the alias ends up doing

const route = {
  path: "/users".component: User,
  // My English is too poor
  alias: "/humans".children: {{path: ' '.component: UserList, alias: ['/people'.'list']}}}Copy the code

The route above matches the path below

// - /users
// - /people
// - /users/list
// - /humans/list
// - /humans
Copy the code

So how does an alias exist on vue-Router? How does it work? The vue-router does two things with aliases. The router does two things with aliases

  1. Adding an Alias Route
  2. Recursively update named subroutes

How does vue-Router solve these two problems

Adding an Alias Route

In the router/SRC/matcher/index. The ts 86 to normalizedRecords (routes) standardized version of the array, a number of network stations, is actually in order to facilitate we add an alias, so the default alias, Refer to the following data structure description

/ / the source code
const routes = { path: "/users".alias: "/humans" };
// Vue-router is processed
const normalizedRecords = [{ path: "/users" }, { path: "/humans" }];
Copy the code

Vue-router is also very simple to add an alias route, a for loop, like the following

if ("alias" in record) {
  const aliases =
    typeof record.alias === "string"? [record.alias] : record.alias! ;for (const alias of aliases) {
    normalizedRecords.push({
      // alias route: RouteRecordNormalized}); }}Copy the code

Note a small detail, look at the source code below

const aliases =
  typeof record.alias === "string"? [record.alias] : record.alias! ;Copy the code

Alias is actually an optional attribute in the route interface _RouteRecordBase. Alias is undefined, so it must have a null value, meaning record. Alias must have a value, Don’t may be null or undefined, but actually even record. The alias = undefined | | null, vue – the router is running but complains, Const alias of aliases {//… }

If there is a parent route, the parent route will need to keep the value of originalRecord. This is actually related to updating the parent route recursively

normalizedRecords.push(
  assign({}, mainNormalizedRecord, {
    components: originalRecord
      ? originalRecord.record.components
      : mainNormalizedRecord.components,
    path: alias,
    aliasOf: originalRecord ? originalRecord.record : mainNormalizedRecord,
  }) as typeof mainNormalizedRecord
);
Copy the code

Vue-router has one neat design feature that can be explained here

for (const normalizedRecord of normalizedRecords) {
  matcher = createRouteRecordMatcher(normalizedRecord, parent, options);

  if (originalRecord) {
    originalRecord.alias.push(matcher);
  } else {
    originalMatcher = originalMatcher || matcher;
  }

  originalRecord = originalRecord || matcher;
}
Copy the code

Const routes = {path: “/users”, alias: “/humans”}; For example, for a data structure from the source code above, originalRecord means “/users”.

const normalizedRecords = ["/users"."/humans"];
Copy the code

Its purpose is to make “/ users to generate the Matcher needs and”/humans “(alias) generated by the Matcher, namely originalRecord. Alias. Push (Matcher); This step, “/ user” as normalizedRecord traversed is no originalRecord for the first time, and then through the | | assignment, | | actually can be called selection operator, it will choose the first is true value, for example

console.log(false || 1); / / 1
console.log(1 || false); / / 1
Copy the code

So first traversal, traverse the original “/ users,” originalRecord = undefined | | matcherByUser, The second traversal is originalRecord = matcherByUser | | matcherByHuman, so can the whole traversal of the original will be pointing to “/ users”

Recursively update named subroutes

The recursive update alias subpath uses the multi-tree traversal algorithm (leetCode has a detailed solution, as well as Labuladong). If you extract the source code, you can see that vue-Router4’s recursion comes from the same root as the multi-tree traversal framework

function addRoute() {
  for (const normalizedRecord of normalizedRecords) {
    if ("children" in mainNormalizedRecord) {
      const children = mainNormalizedRecord.children;
      for (let i = 0; i < children.length; i++) { addRoute(); }}}}// Multi-tree traversal framework
const traverse = (root) = > {
  if (root === null) {
    return;
  }
  for (let i = 0; i < root.children.length; i++) { traverse(root.children[i]); }};Copy the code

The reason for the extra loop is that the vue-Router’s alias and original are split at the same time. As mentioned in the previous section, the route will be grouped at the beginning to achieve a closed loop

/ / the source code
const routes = { path: "/users".alias: "/humans" };
// Vue-router is processed
const normalizedRecords = [{ path: "/users" }, { path: "/humans" }];
Copy the code

From this part, we can know that vue-router uses the recursive traversal framework to process the multi-fork tree structure of routes

conclusion

Finally, a few tips for reading vue-Router. When I first looked at the matcher section of the code, I looked at the relationship between each part of the call, and I fell into the detail trap. I wasted a lot of time worrying about the designer’s consideration of part of the source code, and the type of TS. For a quick understanding of some of the source code usage and designers’ considerations, you can try debugging in Chrome. After you know the call relationships between source modules, you can design test cases. For example, the route given in vue-Router documentation is a very good test case. Then run it to Chrome for debugging. Chrome debugging is better than Vs Code debugging. You can see the designers thinking about the source code, debugging this dynamic process, is much more efficient than if you just read the source code

Router4: Router4: Router4: Router4: Router4: Router4: Router4: Router4: Router4: Router4: Router4: Router4: Router4: Router4: Router4

  1. How does vue-Router find vUE components to render? Vue – Router Matcher parsing (1) – Standardized route
  2. How does vue-Router find vUE components to render? Route-router Matcher (