Vue-router: [Feature request] Route groups/multiple route hooks

Created on 23 Feb 2017  路  7Comments  路  Source: vuejs/vue-router

Let's assume part of an app is open for all visitors and the other part is restricted for logged in users.

Currently available options

An example before hook providing the redirect functionality would look like this:

const authMiddleware = (to, from, next) => {
    if (!signedIn) {
        return next('/login');
    }

    return next();
}

And example usage would be like this:

{ path: '/protected1', component: require('./views/Protected1.vue'), beforeEnter: authMiddleware },
{ path: '/protected2', component: require('./views/Protected2.vue'), beforeEnter: authMiddleware },
{ path: '/protected3', component: require('./views/Protected3.vue'), beforeEnter: authMiddleware },

There are a few problems with this approach. For example it's difficult to add a second hook to the route. One would have to do something like this:

beforeEnter: (to, from, next) => {
    if (!signedIn) {
        return next('/login');
    }

    if (anotherCondition) {
        return next('/someURL');
    }

    return next();
}

which introduces code duplication.

Proposal

I want to propose simplifying above code in two possible ways:
One way to approach this would be to allow for beforeEnter to be an array eg:

{ /*...*/ beforeEnter: authMiddleware },
{ /*...*/ beforeEnter: authMiddleware },
{ /*...*/ beforeEnter: [authMiddleware, anotherMiddleware] },

You would still have to explicitly set the hook on each of the protected routes, but this simplifies adding another one.

Second option would be to introduce a concept of route groups similar to what Laravel offers:

Route::group(['middleware' => 'auth'], function () {
    Route::get('/', function ()    {
        // Uses Auth Middleware
    });

    Route::get('user/profile', function () {
        // Uses Auth Middleware
    });
});

It may look something like this:

new VueRouter({
    routes: [
        { path: '/unprotected', component: require('./views/Unprotected.vue') },
        new RouteGroup({beforeEnter: authMiddleware}, [
            { path: '/protected1', component: require('./views/Protected1.vue') },
            { path: '/protected2', component: require('./views/Protected2.vue') },
            { path: '/protected3', component: require('./views/Protected3.vue'), beforeEnter: anotherMiddleware }
        ]
    ]
});

Most helpful comment

Middleware arrays should be the way to go..

All 7 comments

Or maybe it can be done using nested routes?
Is this a correct approach?

{
    path: '',
    beforeEnter: authMiddleware,
    children: [
        { path: '/protected1', component: require('./views/Protected1.vue') },
        { path: '/protected2', component: require('./views/Protected2.vue') },
        { path: '/protected3', component: require('./views/Protected3.vue'), beforeEnter: anotherMiddleware },
    ]
}

It feels kinda hacky but it appears to work.

The usual approach to such things as enforcing signin for certain routes is to use meta props. There's even an example in the docs:

https://router.vuejs.org/en/advanced/meta.html

@LinusBorg Thanks, I haven't thought about that.

So I suppose I can do:

{
    path: '',
    meta: { requiresAuth: true }
    children: [
        { path: '/protected1', component: require('./views/Protected1.vue') },
        { path: '/protected2', component: require('./views/Protected2.vue') },
        { path: '/protected3', component: require('./views/Protected3.vue'), beforeEnter: someHook },
    ]
}

yep.

I like the @KKSzymanowski proposition ! Why not propose this possibility too ? It seems more simple and intuitive that using "meta"..

{ /*...*/ beforeEnter: authMiddleware },
{ /*...*/ beforeEnter: authMiddleware },
{ /*...*/ beforeEnter: [authMiddleware, anotherMiddleware] },

Middleware arrays should be the way to go..

Why hasn't this been done yet?

Was this page helpful?
0 / 5 - 0 ratings