Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto Route - Automatically generated routes. #6

Open
4 of 7 tasks
webnoob opened this issue Feb 19, 2020 · 34 comments
Open
4 of 7 tasks

Auto Route - Automatically generated routes. #6

webnoob opened this issue Feb 19, 2020 · 34 comments

Comments

@webnoob
Copy link

webnoob commented Feb 19, 2020

RFC (Request for Comments) Template

Please select your type of RFC (one or more):

Put an x in the boxes that apply

  • Change ?
  • Method ?
  • Behavior ?
  • Research ?
  • Innovation ?

Other

Does this introduce a breaking change?

Put an x in the box that applies

  • Yes
  • No

Proposed RFC

Generate route definitions automatically, by reading the folder structure of the pages directory with the option to override on a route level using meta files.

Requirements

Configurable as to whether it'll generate routes or not (default Off).
quasar.conf.js

framework: {
  autoRoute: boolean | object
}

The following folder structure:

└── src/
│   └── pages/
│       ├── pages.vue
│       ├── dashboard/
│       │   └── dashboard.vue
│       ├── user.vue
│       ├── user/
│       │   ├── index.vue
│       │   ├── query.vue
│       │   └── __underConstruction.vue
│       ├── blog_category.vue 
│       ├── blog_category.meta.js 
│       ├── blog_category/
│       │   ├── index_[post-id].vue
│       │   └── index_[post-id].meta.js
│       ├── games!.vue
│       ├── games!.meta.js
│       ├── !.vue
│       └── !.meta.js
└── quasar.conf.js

Generates the following routes:

[
  {
    name: 'pages_index',
    path: '',
    component: () => import('pages/pages.vue')
  },
  {
    name: 'pages_dashboard_index',
    path: '/dashboard',
    component: () => import('pages/dashboard/dashboard.vue')
  },
  {
    name: 'user_index_parent',
    path: '/user',
    component: () => import('pages/user.vue'),
    children: [
      {
        name: 'user_index',
        path: '',
        component: () => import('pages/user/index.vue')
      },
      {
        name: 'user_query',
        path: 'query',
        component: () => import('pages/user/query.vue')
      },
      { /* NOTE: Route omitted from production build */
        name: 'user_underconstruction',
        path: 'underconstruction',
        component: () => import('pages/user/__undercontruction.vue')
      }
    ]
  },
  {
    name: 'blog_category_parent',
    path: '/blog/:category',
    component: () => import('pages/blog_category.vue'),
    children: [
      {
        name: 'blog_category_index',
        path: ':post-id?',
        component: () => import('pages/blog_category/index_[post-id].vue')
      }
    ]
  },
  {
    name: 'games_wildcard',
    path: '/games*',
    // Not lazy loaded as the meta file would say `lazyLoad: false`
    component: 'pages/games!.vue' 
  },
  {
    name: 'wildcard',
    path: '/*',
    component: () => import('pages/!.vue')
  }
]

Routing Conventions

  1. If a .vue file and a path below it match names (including brackets and underscores), the .vue file must be a router-view and the folder beneath it are its child pages. If in the children, there is an index.vue file, it is considered "pathless" and would be the first page to be shown when navigating to that route. If there is a .vue file which matches the parent folder, that'll be the default route otherwise (when no index vue file exists) and will also be considered pathless.

  2. _foo - an underscore in front of the word means the word is a parameter. So, in the example vue file baz_foo.vue, "foo" is a parameter for "baz". There can be multiple parameters such as baz_bar_foo.vue.

  3. [foo] - brackets around the word means it is optional. A path or a parameter can be optional. /[foo] would be an optional path. In baz_[bar].vue, "bar" would be an optional parameter for "baz".

  4. /foo! - an exclamation mark after a folder name means it is a wildcard path. So, a folder with the name /foo! will translate to /foo/*. In most cases, you'll also need to add a same named .meta.[js|ts] file below the wildcard path (folder) to add your specialized routing rules, including any reroutes to a 404 page, where necessary.

  5. A same-named .meta.[js|ts] file will be a container for any additional overriding, validation, guarding, etc. More details on this is below.

Example Meta File / Override route info

index_[post-id].meta.js

export default {
  lazyLoad: true, // Should this route be lazy loaded?
  route: {
    beforeEnter: (to, from, next) => {
      console.log('Im in a route guard!')
      next()
    }
  }
}

With the above meta file defined, the route for pages/blog_category/index_[post-id].vue will now look like:

{
  name: 'blog_category_index',
  path: ':post-id?',
  component: () => import('pages/blog_category/index_[post-id].vue'),
  beforeEnter: (to, from, next) => {
    console.log('Im in a route guard!')
    next()
  }
}

Everything under route: { } will be assumed as standard vue-router properties and will in turn be added directly to the route.

Additional properties will go on the same level as route: {}.

Meta File MeProperties

  • lazyLoad: boolean = true - Whether the route should be added as a lazy loading route or not.
  • parameters: ['param1', 'param2', 'param3'] - These parameters will be added to the route, for instance a file some-path.vue with this meta file property set would have a path generated like some-path/:param1/:param2/:param3. The idea for this is to avoid long file names when a route needs many params.
  • route: RouteConfig = {} - RouteConfig propertes which will be attached to the generated route i.e beforeEnter.

Layouts &

This is dealt with in point 1 of the Routing conventions above. It is up to the developer to chose what file they would like to use as a layout and also how that file is named. For instance, a layout file could be defined like so:

└── src/
│   └── pages/
│       ├── pagesLayout.vue
│       └── pagesLayout/
│           └── index.vue
└── quasar.conf.js

It would then be clear to the users this was a layout but because there is a folder matching the file name, it would know that there is a <router_view /> contained within that file and the files below the same-named folder are the router-view's child pages.

To index.vue or not to index.vue?

It would be up to the developer to decide if they would like to use index.vue as the route / pathless view of that route. Point 1 of the convention again gives us a way by allowing us to either use index.vue or a file with the same name as the parent folder. index.vue if specified will always take precedence over a same named file.

Dev only pages (__something.vue)

These will only be generated in the routes.[js|ts] file when running in dev mode e.g quasar dev.

Development Notes

We will refer to the UI Kit for code generation regarding fetching of files and routing (see: https://github.com/quasarframework/quasar-starter-kit-ui/blob/master/template/ui/dev/src/router/pages.js) however, we will need to make sure the call to require.context() uses the fourth param lazy so as to honor lazy loading components.

@webnoob

This comment has been minimized.

@rstoenescu

This comment has been minimized.

@rstoenescu

This comment has been minimized.

@webnoob

This comment has been minimized.

@webnoob

This comment has been minimized.

@marcelo-gondim

This comment has been minimized.

@webnoob

This comment has been minimized.

@webnoob

This comment has been minimized.

@webnoob

This comment has been minimized.

@stgunholy

This comment has been minimized.

@webnoob

This comment has been minimized.

@webnoob

This comment has been minimized.

@marcelo-gondim

This comment has been minimized.

@webnoob

This comment has been minimized.

@rstoenescu

This comment has been minimized.

@webnoob
Copy link
Author

webnoob commented Mar 3, 2020

Hi All,

I've updated the main RFC post with a complete re-think based on @smolinari and I bashing it out in discord to try and cover all possible things that would be required.

Looking forward to the feedback.

@stgunholy

This comment has been minimized.

@webnoob

This comment has been minimized.

@smolinari

This comment has been minimized.

@stgunholy

This comment has been minimized.

@SirAuron
Copy link

Hi all!

So my colleague @IlCallo asked me to share my opinion on this RFC since I've worked with Nuxt.js, and my thoughts are based on my experience with that framework .
I'll try to be brief and only talk about things that, in my opinion, should be revised (btw, I love the Dev only pages feature).

Directory structure

My main concern here is that this type of structure can be a little bit confusing to the developer.
An example: if the app has many pages, the page directory can get overcrowded very quickly, since each route can have a .vue component, its meta file and an associated folder.

I think it's better to have all logic regarding a single route inside its own folder. To me, this means that (using the RFC example):

  1. the blog_category.vue page component file should be contained inside the blog_category folder and be renamed to index_category.vue;
  2. also the blog_category-meta.vue should be moved inside the the blog_category folder;
  3. to specify a default child route component, the only option left is to use the .vue file which matches the parent folder as described above in the Routing Conventions 1.

Layout

I think it would be be nice to have a separate folder in which to store layouts, so that a single layout can be used in different route components.
This would also enable the possibility to dynamically change the layout of a route given a particular state (maybe a logged in user, a user with different privileges, etc...).

.meta.[js|ts] vs -meta.js

A thing that I've not understood is the duality mentioned in the above title concerning the meta info for the route. I think that a user should be forced to use only one of the two ways (I'm assuming that the above syntax is used for the same purpose).
If that's the case, I would drop the possibility to use the -meta.js version and force the usage of .meta.[js|ts].

@webnoob
Copy link
Author

webnoob commented Mar 11, 2020

Hey!

Thanks very much for the feedback! We appreciate you taking the time for it.

Structure
I agree with your points about the directory structure. One of the issues which was raised before moving down this road with mappings was that there would be a lot of index.vue files and hard for a developer to easily navigate to their chosen files using their IDE's file lookup but given you're adding the param to the index files i.e index_category.vue that'd get around that.

Layout
Couldn't this be achieved using the meta file and set the component for that route? You could have a factory function which returns the correct component for layout based on whatever factors.

meta File
Not sure I understand this. The [js|ts] just means it could be a someRoute-meta.js file or a someRoute-meta.ts file. Meaning it'll work as either Typescript or JS. Does that clear up your concern on that one?

@IlCallo
Copy link
Member

IlCallo commented Mar 11, 2020

Talking about the last point: I think the problem is the .meta or -meta thing (notice the first char). It may also be a typo, is there a logical difference between the two?

@webnoob
Copy link
Author

webnoob commented Mar 11, 2020

Ah, whoops. It should be someRoute.meta.js (or .ts).
I changed it after adding so must have missed some examples. Will sort.
Edit: Updated the RFC to show .meta.js now.

Just to clarify as well. We moved away from -meta because it would stop people adding a file like something-meta.js to that folder and we didn't want people to be limited. Having it as .meta.js seemed to be more fitting.

@SirAuron
Copy link

SirAuron commented Mar 11, 2020

Hi,
about the last point, yeah that's exactly what I was thinking about and that change is perfect.

About the layout, I didn't though about that, but I think that yours could be a neat solution.

About the structure I see your point. A possible solution would be to move all the child views inside their own folder and let the main component, which should be rendered by default, keep its name instead of being renamed to index.
But then you would have to deal with a lot of sub folders I guess...

@webnoob
Copy link
Author

webnoob commented Mar 11, 2020

RE: Meta and Layout - Great!

But then you would have to deal with a lot of sub folders I guess...

I feel, when it comes to auto routing, that there is always going to be a dilemma like this because we're trying to automate something. When it comes to keeping its name, point 1 of the spec does allow for the default view having the same name as it's parent or using index.vue.

So it's about this point of nesting the children. One option could be to add an option to the meta file so that you can configure where the component(s) are: i.e { childDir: 'myChildFolder' } then if present the parser would look for the children in that folder tree. It would then be up to the dev to decide whether they want a long list of files or nested directories. I'm not sure.

With your experience in Nuxt, how do they avoid this kind of thing?

@SirAuron
Copy link

Nuxt uses the same solution you proposed in the RFC: they use an example.vue file and then searches if there is a directory named example on the same directory level. If this directory exists, then the components inside are used as child components for the nested routes.
But I do not like that system for the same motivations I've reported in this discussion.

The only difference is that they include the information you include in the .meta.[js|ts] directly inside the example.vue file in a specific object property which is later extracted and analyzed at compile time.
Even thought this reduces the number of files you have to create, it does not give the developer a visual feedback on which components have custom routing properties or guards, so I prefer your system of using an external file to accomplish this task.

I think that another solution for the sub folder issue would be to just place all .vue components for nested routes directly inside a special folder such as (for example):
[specialChildrenFolderPrefix][childrenFolderName]
where [specialChildrenFolderPrefix] is a group of special chars used just for identifying the folder for nested routes components.
In this way we have only a single folder for all child components and still use the other conventions inside the special folder.

What do you think about this?

@webnoob
Copy link
Author

webnoob commented Mar 11, 2020

Right, I see.

We initially thought about adding the routing info into the vue file but didn't want to be parsing all the files just for the routing info but you make a good point, having the meta also allows easy visibility of routing data. Glad to see we went the right way with that.

RE: Children. EDIT: Removed. Misunderstood. Re-thinking :)

@msolanogithub
Copy link

Hi every one.

This idea is amazing to big projects to order and centralize these recurring actions. i'm working in a front side modular project using Quasar as base. beginning i was thinking the same, generate routes according to exiting files but bellow i was needed manage this actions manually for add or config more especific actions. So i was code a way to auto load not just Routes, too Stores (Vuex) and this it's working so well for my and my working team.

this is a example how i doing:

{
permission: '', //I'm using permissions to access
activated: true, //Enable/disable page
path: '/path/name',
name: 'route.name',
layout: () => import('src/layouts/master'),
page: () => import('src/pages/index'),
title: '<page.title>',//This is a title to final user, same i'm using to load as meta title
icon: 'fas fa-chart-pie',
authenticated: true,//Work with authention module, and require login to access
breadcrumb: ['leads.leads'] //generate a breadcrum with pages names.
}

With this method, I create and manage routes with more order and faster, I also allow this information in $ route.meta to be accessed when necessary.

What do you think about this?

@webnoob
Copy link
Author

webnoob commented Mar 12, 2020

@michaelsoup Thanks for the thoughts. Whilst this might work for your team, I'm not sure of it's scalability for the needs of Quasar. That being said, it's not really on topic of this RFC - we are going down the file structure route, we're just trying to determine how the community would like us to do that.

@rAugustos
Copy link

rAugustos commented Mar 16, 2020

@webnoob nice job man.

Seeing the functionality being theoretically created is just fantastic.

When the feature is released, this issue must to appear at the bottom of the documentation page because this participation has been essential to developers and the community.

@tanthammar
Copy link

Very eager to know the progress on this ... :)

@webnoob
Copy link
Author

webnoob commented Apr 1, 2020

Just waiting on @rstoenescu to take a peak and provide his thoughts but I'm pretty happy with the spec at the moment.

I'll start work ASAP.

@vuvandong
Copy link

Horrible route if so much page, layout! Automatic generator route is needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests