Skip to content

Allow components to define their routes in their definition file instead of having them all in one place #298

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

Closed
asynkayo opened this issue Dec 19, 2015 · 40 comments
Labels
feature request needs RFC This feature request needs to go through the RFC process to gather more information

Comments

@asynkayo
Copy link

Since components are already taking care of not polluting other places, I believe it would be really nice to have components declare their own routes (subroutes actually) in their own space.
This would really help for huge apps and it would favor components reusability.
I was thinking of a 'routes' object in the component's definition object but this could be in a vue file
as well.

@asynkayo asynkayo changed the title Allow components to define their routes in its definition file instead of having them all in one place Allow components to define their routes in their definition file instead of having them all in one place Dec 19, 2015
@b12k
Copy link

b12k commented Dec 22, 2015

Very arguable feature.
I personally do no like this approach. It kind of Symfony and some .Net MVC workarounds...
I like to open a single file with routes and see how app works.

@asynkayo
Copy link
Author

Well of course, just like any features they are arguable.
I guess it's not about your personal taste though but potential flexibility at zero cost.
Components are exactly that.
I'd like to open only one file to see how a component work.
Adding dev tools to dump all the routes of an app should also be quite easy...

@jonagoldman
Copy link

It can be useful if you have big app with totally isolated parent components. For example if you have a Public component (not authenticated users) and a Private component (authenticated users), then maybe you can split the routes in two. But in general it's better to have a file where you can see all the possible routes.

@amirrustam
Copy link

I can see how this would be useful for larger apps. Coming from the Python world, the popular Django framework does something similar. There is a root route map, and you can include route maps to individual root routes.

So here is a rough Django inspired proposal:

route.map({
  '/foo' : {
    component: Foo
  }
})

And the Foo component can provide the nested routes with in a map property of the already implemented route property:

var Foo = Vue.extend({
  // ...
  route: {
    map: {
      'bar/:id' { component: Bar }
    }
 }
})

The route /foo/bar/:id would route to the Bar component.

I thought this up quickly, so I'm not sure what consequences might come out of this method of defining routes.

@Jnesselr
Copy link

I do like the idea of being able to separate them like this, but the v-link would have to be the full path and not the partial path, in case I needed to link to something outside of it. This would, in my mind, make a sub-component possibly depend on another component.

Other than that issue, I do like the idea, because it lets me get a high level overview of the routes without having to dive in to any particular one. When you have a ton of components and you're dealing with routes and subroutes, it gets a bit tedious.

@perkola
Copy link

perkola commented Mar 4, 2016

While it is arguable to keep all routes and sub-routes together to improve readability, is there anyway to get around having to import all the components used in that routes file? For example:

import Archive from './Archive.vue'
import ArchiveIndex from './components/archive/Index.vue'
import ArchiveShow from './components/archive/Show.vue'

...

router.map({
    '/archive': {
        component: Archive,
        subRoutes: {
            '/': { component: ArchiveIndex },
            '/:slug': { component: ArchiveShow }
        }
    }
})

Somehow it feels like the components of the sub-routes should be imported in the parent component.

@chmln
Copy link

chmln commented Mar 9, 2016

is there anyway to get around having to import all the components used in that routes file?

If you use webpack you can import components into router.map() like this
`

'/register': {
    name: "register",
    component: resolve => require(['./Register.vue'], resolve)

},

'/login': {
    name: "login",
    component: resolve => require(['./Login.vue'], resolve)
},`

@perkola
Copy link

perkola commented Mar 9, 2016

@chmln does Browserify support this? I can't seem to find it in the documentation.

@javisperez
Copy link

@perkola yes, browserify support it, i'm using it with gulp, here's an example of how i'm doing it:

router.map({
    '/manage': {
        component: require('./manage/manage.vue')
    }
});

@airtonix
Copy link

airtonix commented Jul 26, 2016

modules providing their own routes is how Django works too.

Promotes modularising complete functionality.

@perkola, the browserify example doesn't actually do the same thing as the webpack example. read more here: http://router.vuejs.org/en/lazy.html

@lkiarest
Copy link

It's helpful when we need to add subRoutes at runtime, when our webapp supports widgets that are developed by 3rd parties and dynamically loaded.

@inssitu
Copy link

inssitu commented Aug 23, 2016

I really like the idea... See this in a component would be awasome

route: {
  name: 'newPosts',
  path: 'posts/news'
}

@jasonbodily
Copy link

jasonbodily commented Nov 17, 2016

There is a lot of component-specific logic for routes that goes in the activate or beforeActivate of the route. So if you have one routes file, you'll end up having a lot of component specific logic there. This makes me cringe. Am I right in reading it this way?

EDIT: I didn't realize the components hold the 'beforeRouteEnter' or resolve functionality. New paradigm to me, still trying to figure out how I feel about it. But that changes my comment~

@nkostadinov
Copy link

We should be just able to modify the routes at runtime and everyone will handle the routing as he pleases.

@rickhall
Copy link

I'm new to Vue and Vue Router, but my first thought when starting to play around with nested routes was, "Wow, this is really unmodular and won't scale very well." The fact that my component doesn't contain its own effective "template" and I instead have to look into and/or modified some global configuration to get what I want seems really odd to me.

+1 for adding nested routes directly into components.

@simplesmiler
Copy link
Member

simplesmiler commented Nov 28, 2016

@rickhall I was thinking this way too. But after getting mileage with router I changed my mind. Routes being disconnected from the "controllers" (the route-handling components) is what makes the setup modular.

  1. It reflects the fact that the address bar is a unique resource.
  2. It makes your controllers not rely on presence of each other.
  3. It makes your controllers reusable in different contexts (with different host and content).
  4. It still allows you to reuse "route subtrees" at will.

@rickhall
Copy link

I think there are potentially two different ways to view sub-routes: 1) treat them as internal implementation details of the component or 2) treat them as API of the component.

I was coming at it from (1), but I can certainly see that (2) makes sense too. But only having option (2) as an approach effectively forces me into exposing stuff as API, even when that might not be my intent.

The mere fact that I can bind data and/or register for events in nested router-view elements indicates that the component is expecting something specific to happen and the contents of the router-view elements cannot be freely substituted without impacting the component behavior.

@taotao365s
Copy link

taotao365s commented Dec 16, 2016

yeah, I need too.

just open createMatcher method, right? or you can create new method which called refreshRoute in VueRouter

👍

@nkostadinov
Copy link

It will be really nice if components could define their own routes/subroutes. It will make the routing much more flexible and consistent because only registered components will "add" routes to the router.

@coding2012
Copy link

coding2012 commented Feb 5, 2017

While there may be some odd work-arounds, but I really would love to be able to do something like this:

main.ts

new Vue({
  el: '#app-main',
  router: new VueRouter({
    routes: [
      { path: '/', component: HomeComponent },
      { path: '/products', component: ProductsComponent },
      { path: '/categories', component: CategoriesComponent },
    ]
  }),
  components: {
    'navbar': NavbarComponent
  }
});

categories.ts

@Component({
  template: `<div>
  Categories
  <router-view></router-view>
</div>
`,
  router: new VueRouter({
    routes: [
      { path: '', component: ProductsComponent },
      { path: 'somethingElse', component: NavbarComponent },
    ]
  }),
  components: {
    'products': ProductsComponent
  }
})
export class CategoriesComponent extends Vue {

This is an incomplete, non-working example, obviously, but just to illustrate.

@aaroncmoore
Copy link

I would like to advocate for this feature. I am new to Vue and Vue-Router and so far I've enjoyed my experience with both. However, after re-structuring my growing app and trying to break up the quickly growing router file, I found this limitation frustrating.

For myself, an App's structure is reflected in it's folder and file layout. I expect this from any project I must maintain. For example, to find the Account Preferences page and components, I do not look in the router file to find it's path and behavior, I look in the Pages/AccountPreferences folder and open AccountPreferences.Vue.

That being said, I can appreciate a single file approach for smaller apps. I would just like to see Vue-Router offering an alternative option for people like me that would like components to take ownership of their route definitions.

@joelmandell
Copy link

@aaroncmoore I was looking for this...So I found in the documentation router.addRoutes().
So I 'inject' router in main.js to the const app = new Vue({}). And then in my components i use this.$router.addRoutes(). I works for me

@joelmandell
Copy link

joelmandell commented Apr 4, 2017

Ooh...I just now found out that it doesnt replace existing routes with the same path names. It's something I need. Turns out I have to wait for this one #1129 :)

@mitar
Copy link

mitar commented Jul 15, 2017

For Meteor, @Akryum made this great simple addition, router factory, which allows one to register routes lazily, and then at the end all routes are defined at once.

You can define then route inside a component like:

<template>
  <div>My component.</div>
</template>

<script>
  import Vue from 'vue';
  import {RouterFactory} from 'meteor/akryum:vue-router2';

  const component = {
    // ... component code
  };

  RouterFactory.configure((factory) => {
    factory.addRoutes([
      {
        path: '/',
        name: 'home',
        component,
      },
    ]);
  });

  export default component;
</script>

You just define a set of callbacks which are called then all together.

@nkostadinov
Copy link

nkostadinov commented Jul 18, 2017

Adding a <routing> tag in Vue components also will be very handy for a component to define its own routes(subroutes)

@rjwittams
Copy link

I think this issue is fixed by 759df36 ?

@vuejs vuejs deleted a comment from psi-4ward Oct 15, 2017
@mrjones2014
Copy link

any chance of this being implemented? I have a large Vue project and having to manually add all the routes to a single file is getting hard to manage; it's also not the obvious place to look for new team members. I would LOVE to see this feature implemented.

@javisperez
Copy link

javisperez commented Nov 1, 2017

@mrjones2014 I dont know if tit would help, but what I do for mid or large projects is that I have a singleton class with a route and child methods, which writes the routes into an object and then just pass that object to VueRouter, works great and that way each component can have its own route :)

I'll try to make a gist later for it and place it here, might help some guys.

@mrjones2014
Copy link

@javisperez do you still have to maintain a routes list globally somewhere, or can it somehow be called from components themselves on register? I'd definitely like to take a look at that gist. Ideally, I'm looking for a solution that allows me to somehow specify a component as a "top-level" component (i.e. one that represents a complete UI screen on the frontend), and if specified as such, require that it also specify a route property (which ideally could be either a string or an array of strings).

@edgarnadal
Copy link

@mrjones2014 we (@javisperez and I) have released the package vue-tidyroutes with our approach to solving this issue.

Please take a look on it: https://github.com/edgarnadal/vue-tidyroutes

Feedback is highly appreciated.

@mrjones2014
Copy link

@javisperez @edgarnadal is there a way to use this from within component files in the single file component (*.vue file) format?

@javisperez
Copy link

@mrjones2014 yes, check this basic example: https://github.com/edgarnadal/vue-tidyroutes/blob/master/example/component1.js that can be used on a .vue file, like this;

component1.vue

<script>
import VueTidyRoutes from 'vue-tidyroutes';

const Component1 = {
    name: 'component1',

    data() {
        return {
            foo: 'bar'
        };
    }
};

// Your routes definition here
VueTidyRoutes.route('/component1', {
    name: 'component1',
    component: Component1
});

export default Component1;
</script>

<template>
<div>
    <h2>Component1</h2>
</div>
</template>

@mrjones2014
Copy link

@javisperez heh, duh. The routes don't seem to be working if I import the components through an index.js file; do I have to import the components each individually, directly in my main.js file?

@javisperez
Copy link

@mrjones2014 🤔 it should be working just fine on an index.js, we are actually using it on some large projects with no problem. Please feel free to open an issue (https://github.com/edgarnadal/vue-tidyroutes/issues) with some reproduction steps or links, so we can have a look; doing it here would be off topic :)

@mrjones2014
Copy link

@javisperez LOL nevermind; I forgot to set mode: 'history' and was using real URLs

@MeirionHughes
Copy link

MeirionHughes commented Feb 8, 2018

@rjwittams comment seems to have gone unnoticed - unless I'm mistaken, from the looks of it 759df36 solves the nested router problem (landed in 3.0.1) at the component level.

[edit] doesn't look like it solves navigating to a route (from the root level) into the nested routers.

@JoeyHuang1
Copy link

The original feature request should help a lot for component encapsulation in large project. Without it, need to know how the sub-component internal (the route info) and put it in the top level, which is harder to reuse a component. Would like to see such feature in new Vue version, or integrate the TidyRoutes implementation into Vue.

@RickMeijer
Copy link

RickMeijer commented Jul 19, 2018

I'm a bit insecure posting this, since I'm just starting out with Vue, and I'm not terribly bright to begin with. It seems too obvious, making me feel like I'm missing something (either in the discussion or in my implementation) but my current solution is this:

// components/component.vue
import SomeChildComponent from './';

export default {
  routes: [
    { path: "/somechildpath", component: SomeChildComponent },
  ]
};

And in my main routes file

// router.js
import Vue from "vue";
import Router from "vue-router";
import Component from "components/component.vue";

Vue.use(Router);

export default new Router({
  mode: "history",
  routes: [
    {
      path: "somepath",
      component: Component,
      children: Component.routes
    }
  ]
});

It appears this can be nested as deep as you want/need. So basically my toplevel component exposes child routes that are being set in that component. I'm a big fan of how angular does this esp. combined with lazy loading.

[edit]Of course it's not necessary to add a routes property to your default export; there are several ways to export that; but principle seems to remain the same, no?[/edit]

@kferrone
Copy link

I actually have already done this before. I have a project which includes the route info inside the component. However it is not using .Vue files. Here is a good example: https://github.com/kferrone/kferrone.github.io/tree/master/collections/_views/contact-me

@posva
Copy link
Member

posva commented Mar 11, 2021

Given the current state of this issue, there hasn't been any interest in implementing it in core but it seems some people like it while others don't. Therefore, it would be a nice addition as a plugin

If anybody still thinks this is worth including in core, open a discussion or an RFC in the vuejs/rfcs repository to continue the discussion!

@posva posva closed this as completed Mar 11, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request needs RFC This feature request needs to go through the RFC process to gather more information
Projects
None yet
Development

No branches or pull requests