What is automatic route injection

The concept of automatic route injection was learned from NUxT. Instead of manually entering a module each time in router.js, we automatically generate router.js based on the file directory format

We made this feature a separate Webpack plug-in and improved it, and implemented all the core functions of vue-Router

More detailed usage guidelines and documentation can be found in our Github repository

Let’s take a simple example, let’s say your directory looks like this

SRC ├ ─ ─ views │ ├ ─ ─ the Login │ │ └ ─ ─ Index. The vue │ └ ─ ─ the User │ ├ ─ ─ the Account │ │ └ ─ ─ Index. The vue │ ├ ─ ─ Home │ │ └ ─ ─ Index. The vue │ └ ─ ─ Index. VueCopy the code

The rule is simple: if the first layer of the directory is index. vue, the directory name is the name of the current route, and if the subfolder is the second layer route, the automatically generated router.js will look like this

{
  component: (a)= >
    import('@/views/Login/Index.vue'),
  name: 'login'.path: '/login'
},
{
  component: (a)= >
    import('@/views/User/Index.vue'),
  name: 'user'.path: '/user'
},
{
  component: (a)= >
    import('@/views/User/Account/Index.vue'),
  name: 'user-account'.path: '/user/account'
},
{
  component: (a)= >
    import('@/views/User/Home/Index.vue'),
  name: 'user-home'.path: '/user/home'
}
Copy the code

It is important to note that the router.js generated is not necessary to be included in version control, as it is automatically generated during the first build of the project, whether in development or production. For example, if your project uses Git or ESLint, you should put it in.giti Gnore and. Eslintignore

Why use automatic route injection

  • convenient

Instead of referring to a module every time, just create a folder that router.js will automatically generate

  • Unified Route naming

This problem would not exist if there was a complete code review, but we made it a little easier by just naming the code Review folder. The generated route path will be named after the hump, and the generated name will be named after the hump and will be hyphenated – to connect the routes of different levels

  • Unified Routing Hierarchy

As the example in the picture, we can not determine the level of the route from the file name, and often write a level 2 or 3 route and level 1 route in the same layer of the route, which is very non-standard and inconsistent with logic

Compare the hierarchical routing with automatic injection

SRC /views ├─ Index. Vue ├─ NotFound. Vue ├─ Withdraw <! - the first level - > │ ├ ─ ─ Index. The vue │ └ ─ ─ the Result │ ├ ─ ─ the Description <! ├ ─ ├ ─ garbage <! ├ ─ ├ ─ garbage, ├ ─ garbage <! ├ ─ 2nd class --> ├ ─ 2nd classCopy the code

You can see the hierarchy of routes in the directory structure

Let’s look at the generated route again. The route names of different levels are hyphenated, so the hierarchy is clear

{
    component: (a)= > import('@/views/Withdraw/Index.vue'),
    name: 'withdraw'.path: '/withdraw'
},
{
    component: (a)= > import('@/views/Withdraw/Result/Index.vue'),
    name: 'withdraw-result'.path: '/withdraw/result'
},
{
    component: (a)= > import('@/views/Withdraw/Result/Description/Index.vue'),
    name: 'withdraw-result-description'.path: '/withdraw/result/description'
},
{
    component: (a)= > import('@/views/WithdrawHistory/Index.vue'),
    name: 'withdrawHistory'.path: '/withdrawHistory'
},
Copy the code

Why choosevue-router-invoke-webpack-plugin

  • Good unit testing

  • Types support

vue-router-invoke-webpack-pluginUnique routing partitioning thinking in

When we too page, such as project has more than 60 or even 70 single page, the file could not be placed in a directory, usually this time, we will according to the function will be similar to function of routing in a directory, before we did the same, actually do so also do not have what problem, but under the routing automatically injection, we put forward the thinking by another Routing Hierarchy

What is hierarchy? In a simple sentence, the page is divided according to the relative URL address, for example, our home page is as follows

The route of the home page is /, and we take the home page as the root route, so the accessible first-level routes are respectively withdrawal and withdrawal records divided into data, etc. After clicking withdrawal, we entered the withdrawal route /withdraw

After entering the cash withdrawal page, there will be two clickable places, these two places are the secondary page, placed in the sub-folder of the first page, according to the previous saying, the route directory (intercept part) is like this

SRC/views ├ ─ ─ Bank <! - bank card management - > │ └ ─ ─ Index. The vue ├ ─ ─ DivideData <! ├ ─ ├ ─ garbage <! ├─ Index. Vue <! ├── BankDetails <! - the withdrawal view card information - > │ │ └ ─ ─ Index. The vue │ ├ ─ ─ the Description <! ├ ─ ├ ─ garbage <! - the withdrawal page - > │ └ ─ ─ Index. The vue └ ─ ─ WithdrawHistory <! ├ ── ├ ─ ├ ─ ├ ─ ├ ─ ├ ─ └Copy the code

In fact, generally so divided down, similar functions will be in a folder below, but also to achieve the idea of functional routing, and this level division is clear, it is easy to see the affiliation of the route

But sometimes also can have a trouble, is that some pages may appear below the current level, may also occur in another level below, according to the feature points also has this, is a function may exists between two function point, this kind of situation can actually consider at what level of weight a little heavy or from a user’s click custom, which position will be a little more It’s just below that level

vue-router-invoke-webpack-pluginUnique file structure in

This is a feature that we added on the basis of NUxT, in order to make it more friendly to encapsulate a single page

For example, if your project does not reference the UI library, many of the business components need to be written by yourself. Except for the common components, which are placed in the components file at the end of the directory, where do you put the rest of the business components corresponding to a single page

SRC /views ├─ Audit │ ├─ Index. Vue │ ├── │ ├─ vue │ ├── images │ ├─ Audit ├.pngCopy the code

Audit is our approval page, which uses an Audititem. vue component that is only used by the current page, and also references an image auditino.png that is only used by the current page. The unique file structure is created for this requirement. But it is worth mentioning that you also need to set ignore in the plugin to ignore directories that are not parsed, such as this

plugins: [
  new VueRouterInvokeWebpackPlugin({
    dir: 'src/views'.alias: '@/views'.language: 'javascript'.ignore: ['images'.'components'.'template.vue']})];Copy the code

Images Components template.vue is ignored and not parsed

Talk about routing permission control

On the front control routing permissions, recently saw a article, feel implementation ideas are a little too complicated, actually has a relatively simple idea, is the back-end routing, given the current user does not have permission then front in beforeEach hooks to match, if the match to have no legal power directly jump 404 or no permissions page, if Vue-router-invoke-webpack-plugin will write this

apis.getForbiddenRoute

export default {
  // Request a list of routes that do not currently have permissions
  async getForbiddenRoute() {
    return ['/single/user']; }};Copy the code
plugins: [
    new VueRouterInvokePlugin({
      // View the directory
      dir: 'demos/src'.// Observe the alias of the directory
      alias: '@/src'.// The current language
      language: 'javascript'.// Generate the location of router.js
      routerDir: 'demos'.// Ignore the folder
      ignore: ['images'.'template.vue'.'components'.'notfound.vue'].// 404 Route address
      notFound: '@/src/NotFound.vue'.// The referenced module
      modules: [
        {
          name: 'apis'.package: '@/apis'}]./ / with scrollBehavior
      scrollBehavior: (to, from, savedPosition) = > {
        if (savedPosition) {
          return savedPosition;
        } else {
          return { x: 0.y: 0}; }}, <! -- Mainly this code -->/* eslint-disable */
      beforeEach: async (to, from, next) => {
        // Determine whether the interface was requested by _cachedForbiddenRoute bound to the static property
        if(! Vue._cachedForbiddenRoute) { Vue._cachedForbiddenRoute = [];await apis.getForbiddenRoute().then(res= > {
            Vue._cachedForbiddenRoute = res;
          });
        }
        // If the address of the current page is in the forbidden list, jump to the 404 page directly
        if (Vue._cachedForbiddenRoute.includes(to.path)) {
          next({
            name: 'notFound'
          });
        } else{ next(); }}}),]Copy the code

But on the other hand, any implementation idea, the front end of the interface data to tamper with or around the past, so we have to back end to prevent a layer

Project implementation Idea

Project implementation is not too complicated, but there are a lot of things to take care of

  • The basic routing
  • Dynamic routing
  • Multilayer nested routines by
  • Multi-level nested dynamic routing
  • Meta substitutes
  • Documents do not conform to the rules of friendly handling
  • Name conversion unification
  • The node in the nativefsModules are very unfriendly

There are a lot of small details to consider, especially if routing is too complex

However, the fs pit in Node was something I didn’t expect, especially on cross-platform, so we abandoned the native FS module and replaced some fs features with Chokidar and FS-Extra

I also learned the AST syntax tree of Vue some time ago, so I learned the idea to try to build an AST, but the method is still different, Vue build syntax tree is to split the element start tag element attribute element character through the re The process of stitching is very complicated. This project will be much simpler. You can generate an AST by reading the file and recursively traversing the directory

Router.js is a syntax tree that builds the string router.js

The project still needs improvement

  • Unit testing

Unit test coverage is now 100%, but I think there are still a lot of slightly more complicated cases that are not covered, and I will look not only at unit test coverage, but at the functional points that I think need to be tested

  • The test environment

The project is connected to Circleci, so it cannot be tested under Windows. The usual development environment is MAC, so we need to study other CI tools that can support Windows and test different Node versions

In fact, there is a bug in Windows, but I found that nuxT also has this bug, so I feel that maybe this is not a bug or a feature, and I will ask for an issue later. I don’t know if it is a problem with my computer, simply put, it is when Fs. watch listens to files and directories You can’t change the name of an existing file directory. Windows will tell you what file is referenced, and you need to end the process to change the file name

  • Friendlier support

The project currently supports node version > 8.15.1, only webpack4, and later webpack3 and the upcoming webpack5

2019-04-19 15:41:31 version >0.2.5

Have support webpack3

More features

In addition to the list of simple routes and set ignore items just mentioned, we also support other core features of vue-Router, including dynamic routing nested routines by global routing guard meta alternatives And other functions, the relevant function points are written in the document, we open warehouse detailed usage and points for attention, you can visit our lot warehouse, if think project is also good, can you give us a star, of course, if you found and expectations are not quite the same as in the use of the issue or bug can always gave us