Automatically generates vUE routing tree and corresponding directory tree and. Vue file

Pain points

Each time a route is added, there are several fixed steps

  1. Find a file directory location
    1. Create a new.vue file and write the basic code for the.vue file
  2. To change the route configuration file, find a hierarchical location and add a new route mapping
    1. You also need to import the new.vue file into the routing configuration file (path pair)
  3. The hierarchy of routes and the directory hierarchy of.vue files make it difficult to ensure one-to-one mapping. We want to achieve absolute one-to-one mapping so that finding files is faster, easier, and more comfortable to look at

Each new route has to go through the process repeatedly, and it is very troublesome to ensure the one-to-one correspondence of the hierarchical structure. Consider automated implementations that automate all of the above with a single command

Achieve the goal

With a single command, such as fe route

  1. All operations required to create a route are automatically completed. For example, add a line containing file import to the route tree. File tree, the corresponding directory to create the corresponding. Vue file
  2. The hierarchical structure of the routing tree and file tree ensures one-to-one correspondence

Technical implementation design

According to a configuration file (object-tree), the target is implemented. Such as:

// Config file fe.config.js(root) (pay attention to hierarchy design)
module.exports = {
  route: {
    login: ' '.index: { // index is treated with /, corresponding to {path: '/'},
      children: {
        index: ' '.template: ' '.taskList: ' '.xxx: {
          children: {
            a: ' '.b: ' '.c: ' '}}},redirect: '/login'.// Optional
      meta: { title: '234' } // Optional
    },
    otherPage: {
      redirect: '/login'.// Optional
      meta: { title: '111111111' } // Optional}}}Copy the code

Then enter a command fe route, which brings up our old friend front-end tool platform: internal front-end tool platform construction

The generated file is as follows

  1. The generated. Vue file is stored in the SRC /view directory and has the same hierarchy as the configuration file
  2. The autoroutes.js routing tree is generated and the hierarchy is consistent with the configuration file

The end result: the hierarchy of file trees, routing trees, configuration files, all maintain a perfect one-to-one correspondence!

  • To add a route, simply add a line to the fe.config.js configuration file. In the implementationfe routeThat will do
// Directory structure:├── ├─ ├─ ├─ ├─ ├.htm// The routing file, detailed as follows, has the same hierarchy as the configuration file└ ─ ─ the view ├ ─ ─ index │ ├ ─ ─ index. The vue │ ├ ─ ─ taskList. Vue │ ├ ─ ─ the template. The vue │ ├ ─ ─ XXX │ │ ├ ─ ─ Dr. Ue │ │ ├ ─ ─ b.v ue │ │ └ ─ ─ C. ue │ └ ─ ─ XXX. Vue ├ ─ ─ index. The vue ├ ─ ─ the login. The vue └ ─ ─ otherPage. Vue// The autoroutes.js hierarchy is consistent with the configuration file
export default[{path: '/login'.name: 'login'.component: () = > import(/* webpackChunkName: "login" */'@/view/login.vue')}, {path: '/'.name: 'index'.component: () = > import(/* webpackChunkName: "index" */'@/view/index.vue'), meta: { title: '234' }, redirect: '/login'.children: [{path: 'index'.name: 'indexIndex'.component: () = > import(/* webpackChunkName: "index-index" */'@/view/index/index.vue')}, {path: 'template'.name: 'indexTemplate'.component: () = > import(/* webpackChunkName: "index-template" */'@/view/index/template.vue')}, {path: 'taskList'.name: 'indexTaskList'.component: () = > import(/* webpackChunkName: "index-taskList" */'@/view/index/taskList.vue')}, {path: 'xxx'.name: 'indexXxx'.component: () = > import(/* webpackChunkName: "index-xxx" */'@/view/index/xxx.vue'),
        children: [{path: 'a'.name: 'indexXxxA'.component: () = > import(/* webpackChunkName: "index-xxx-a" */'@/view/index/xxx/a.vue')}, {path: 'b'.name: 'indexXxxB'.component: () = > import(/* webpackChunkName: "index-xxx-b" */'@/view/index/xxx/b.vue')}, {path: 'c'.name: 'indexXxxC'.component: () = > import(/* webpackChunkName: "index-xxx-c" */'@/view/index/xxx/c.vue'}]}]}, {path: '/otherPage'.name: 'otherPage'.component: () = > import(/* webpackChunkName: "otherPage" */'@/view/otherPage.vue'), meta: { title: '111111111' }, redirect: '/login'}]// A set of templates is also initialized for each.vue file, as follows
// The following is login.vue, where the string 'login' changes dynamically according to the name of the.vue file
<template>
  <div>login</div>
</template>

<script>
export default {
  name: 'login',
  data () {
    return{}},watch: {},
  computed: {},
  created () {
    
  },
  methods: {}}</script>

<style lang=' ' scoped>
</style>
Copy the code

Post the implementation source code

  • Difficulty: Because you need to read the tree, you also need to generate the tree structure. So we’re going to use recursion
    • Recursion requires that the parameters passed in are transitive within the recursion. There’s also recursion to pay attention to the stop condition
// the example of Config, when used, will be found in fe.config.js
// const Config = {
// login: '',
//
// index: {// index will be treated with /, corresponding to {path: '/'},
// children: {
// class: '',
// template: '',
// taskList: '',
// xxx: {
// children: {
// a: '',
// b: '',
// c: ''
/ /}
/ /}
/ /},
// meta: { title: '234' }
/ /},
// otherPage: ''
// }

/** * Generate the corresponding route and file structure * from the route object in fe.config.js@param{Config: object} The route object * in fe.config.js@return No} {* /
module.exports = (Config) = > {
  const fse = require('fs-extra')
  const Tpl = require('./tpl.js')

  const createFile = (path, name) = > {
    const realPath = './src/view/' + path + '.vue'
    fse.pathExists(realPath).then(exists= > {
      if(! exists) { fse.outputFile(realPath, Tpl.vueTpl(name)) .then(_= > {
            console.log(`${realPath}Build successful! `)
          })
          .catch(err= > { console.error(err) })
      } else {
        console.log(`${realPath}Already exist, do not modify! `)}}}const importComponent = (name, parent) = > {
    let arr = [name]
    if (parent) {
      arr = [...parent.split('/'), ...arr]
    }
    / / it must add "", otherwise an error / * webpackChunkName:" ${arr. Join (' - ')} "* /
    return `() => import(/* webpackChunkName: "${arr.join(The '-')}" */'@/view/${parent ? parent + '/' : ' '}${name}.vue')`
  }

  // index/template => indexTemplate
  const getCamel = (name) = > {
    const arr = name.split('/')
    if (arr.length === 1) {
      return name
    } else {
      let str = arr.shift()
      for (const val of arr) {
        str += val.replace(/^\S/.s= > s.toUpperCase())
      }
      return str
    }
  }

  const handleRootPath = (key, parent) = > {
    let path = key
    if(! parent) {/ / root path
      if (key === 'index') { // The index of the root path is treated as /
        path = '/'
      } else {
        path = '/' + path
      }
    }
    return path
  }

  let row = ' '
  const recursion = (obj, parent) = > {
    let content = ' '
    for (const key in obj) {
      const val = obj[key]
      if(! ['[object Object]'.'[object String]'].includes(Object.prototype.toString.call(val))) {
        console.error('Value for key is in the wrong format, can only be string or object')
        return 'Value for key is in the wrong format, can only be string or object'
      } else {
        if (val && val.parent) { // If the parent attribute is configured, the hierarchy can be changed (to make it easier to integrate into older projects)
          parent = val.parent
        }

        const parentVal = parent ? `${parent}/${key}` : key
        createFile(parentVal, key)

        row = `  { path: '${handleRootPath(key, parent)}', name: '${getCamel(parentVal)}', component: ${importComponent(key, parent)}`

        if (typeof val === 'object') { // { meta }
          if (val.meta) {
            row += `, meta: The ${JSON.stringify(val.meta)}`
          }
          if (val.redirect) {
            row += `, redirect: The ${JSON.stringify(val.redirect)}`
          }
          if (val.children) {
            // If there is a parent, save the parent value
            row += `, 
    children: [
    ${recursion(val.children, parentVal)}] `
          }
        }
        content += row + ' },\n'}}return content
  }

  const tpl = '/* This file is automatically generated, please use the self-service editor to format */ export default [${recursion(Config)}]
`

  const routeFile = './src/router/autoRoutes.js'
  fse.outputFile(routeFile, tpl)
    .then(_= > {
      console.log(routeFile + 'Build successful! ')
    })
    .catch(err= > { console.error(err) })
}
Copy the code

Code word is not easy, praise encouragement