owned this note
owned this note
Published
Linked with GitHub
# Auto generate routes
## Feature request
Generate routes definitions automatically, by reading the folder structure of the pages directory.
## Requirements
The following folder structure:
```
pages/
--| user/
------| index.vue
------| query.vue
--| index.vue
--| _param.vue
```
Generates the following routes:
```json
[
{
name: 'index',
path: '/',
component: 'pages/index.vue'
},
{
name: 'user',
path: '/user',
component: 'pages/user/index.vue'
},
{
name: 'user-query',
path: '/user/query',
component: 'pages/user/query.vue'
},
{
name: 'index-param',
path: '/:param?',
component: 'pages/_param.vue'
}
]
```
- index.vue generates "/" route
- route name is related to folder structure
- page with route argument must be defined after everything else on its directory
- conventions above must be configurable ("/" route file name, param page identification, etc)
- **output routes must be inspected with `quasar inspect`**
## Other implementations
### Gridsome
- Gridsome provides an API for route creation
- if we implement it, we need a way to ignore specific pages, so the dev can define its route with the API
- **important for app extensions that wants to show pages focused on dev experience (like static-page-generator)
### NuxtJS
- [NuxtJS lets you define a validator method inside the page component](https://nuxtjs.org/guide/routing/#unknown-dynamic-nested-routes)
- (redirects to 500 error page if an `error` is thrown, or 404 error page if it returns `false`)
- [NuxtJS lets you create nested routes](https://nuxtjs.org/guide/routing/#unknown-dynamic-nested-routes)
- by defining a route page component with the name of a folder on its directory
- the route page component becomes the parent of the pages inside the folder with its name
- [wildcard page component](https://nuxtjs.org/guide/routing/#unknown-dynamic-nested-routes)
- you can use `_.vue` to handle requests that do not match a more specific requests
### vue-cli-plugin-auto-routing
An interesting feature of `vue-cli-plugin-auto-routing`: [route-meta](vue-cli-plugin-auto-routing), lets you define route meta object with a tag on a SFC tag.
### Quasar UI Kit
This is in the Quasar UI Kit:
**src/router/pages.js**
```json=
function kebabCase (str) {
const result = str.replace(
/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g,
match => '-' + match.toLowerCase()
)
return (str[0] === str[0].toUpperCase())
? result.substring(1)
: result
}
function slugify (str) {
return encodeURIComponent(String(str).trim().replace(/\s+/g, '-'))
}
export default require.context('../pages', true, /^\.\/.*\.vue$/)
.keys()
.map(page => page.slice(2).replace('.vue', ''))
.filter(page => page !== "Index")
.map(page => ({
file: page,
title: page + '.vue',
path: slugify(kebabCase(page))
}))
```
then in **src\routes\routes.js**:
```js
import pages from './pages'
const children = pages.map(page => ({
path: page.path,
component: () => import('pages/' + page.file + '.vue')
}))
const routes = [
{
path: '/',
component: () => import('layouts/MyLayout.vue'),
children: [
{ path: '', component: () => import('pages/Index.vue') }
].concat(children)
}
]
export default routes
```
then in **src/pages/index.js**
```htmlmixed=
<template>
<q-page padding class="row justify-center">
<q-list dense class="list">
<div class="text-h4 q-mb-md">Test pages</div>
<q-item
v-for="page in pages"
:key="page.path"
:to="page.path"
>
<q-item-section avatar>
<q-icon name="pages" />
</q-item-section>
<q-item-section>
{{ page.title }}
</q-item-section>
<q-item-section side>
<q-icon name="chevron_right" />
</q-item-section>
</q-item>
</q-list>
</q-page>
</template>
<script>
import pages from '../router/pages'
export default {
created () {
this.pages = pages
}
}
</script>
<style lang="sass" scoped>
.list
width: 700px
max-width: 100%
</style>
```
## Algorithm
Something like this, with adjusts to be made for future user configuration:
1. Given a route array and a folder path, read its files and directories, and store it on an object keyed by `{type}-{name}`, where {type} is either DIR or FILE and {name} is the name of the directory or file.
2. Sort the object by its keys, so that the directories are read first.
3. For each key in the object, do
- if the entry's name starts with '__', ignore it
- if the entry's name starts with '_', generate a route with param (param name: {name})
- if the entry is a directory:
- if there's a file with the same name, store the file's entry, remove it from the object, and go back to step 1, with the file's children as array and the folder path (so that every entry on the folder is a child of the file route)
- else go back to step 1 with the current route array and the directory path
- else, generate the route, where currentPath and currentDir are part of the recursive process:
```js
{
name: slugify(currentPath) + '-' + {name},
path: '/' + currentPath + {name} === 'index' ? '/' : {name},
component: 'pages{currentDir}/{name}.vue'
}
```
- TODO: read page metadata, add routes as a layout route child
## TODO
- how to define named views relationships