Closed asynkayo closed 3 years ago
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.
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...
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.
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.
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.
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.
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)
},`
@chmln does Browserify support this? I can't seem to find it in the documentation.
@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')
}
});
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
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.
I really like the idea... See this in a component would be awasome
route: {
name: 'newPosts',
path: 'posts/news'
}
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~
We should be just able to modify the routes at runtime and everyone will handle the routing as he pleases.
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.
@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.
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.
yeah, I need too.
just open createMatcher
method, right? or you can create new method which called refreshRoute
in VueRouter
:+1:
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.
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.
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.
@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
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 :)
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.
Adding a <routing>
tag in Vue components also will be very handy for a component to define its own routes(subroutes)
I think this issue is fixed by https://github.com/vuejs/vue-router/commit/759df369733414306099099f63518cdb02a0e117 ?
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.
@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.
@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).
@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.
@javisperez @edgarnadal is there a way to use this from within component files in the single file component (*.vue file) format?
@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;
@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?
@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 :)
@javisperez LOL nevermind; I forgot to set mode: 'history'
and was using real URLs
@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.
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.
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]
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
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!
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.