What is the best Vue-Router practice for very large webapplications?
Asked Answered
T

3

39

I have to make a webapplication with many different modules (like a todo-module, document-modules, and a big usermanagement-module for admin users). The total number of pages is > 100. And the module access is different for each user.

I am working with Laravel and Vue-router.

But what is the best practice to do it?

  1. Create a SPA-application, with 1 large vue-router for everything?
  2. For every module a own single "SPA" (with and own vue-router)?
  3. Or another suggestion...?
Twinkling answered 25/4, 2018 at 10:33 Comment(2)
Let's discuss: when using multiple router, wouldn't it be slower when switching between modules all the time?Smirch
Hey angelique000, I have updated the answer after taking queues from the way we handle large-scale JS applications build using Vue.js. Please let me know if it helps you in any way.Jordain
J
41

Little late but I will try to answer the question. This is more an architectural question than just routing level question.

TLDR: You will need a mix of approaches. One approach won't fit.

1. Routing Mode

First, you should determine if you are going with HTML 5 history mode or hash mode It is 2018, and I definitely recommend that you use HTML5 history mode.

If you use history mode, then it means your client-side router will need to work in sync with your server-side router.

2. Micro-frontends

I am not sure if you know this, but micro-frontends is the term you are looking for. Basically, it is your first line of segregation. You should split your app into multiple smaller apps. Each app will have its root component, router, models, services, etc. You will share many of the components (Of course, word very large application is important. And I literally mean it.)

3. Mono-repo considerations

If you have chosen to go ahead with Micro-frontends, then you might consider mono-repo setup using Lerna or Builder.

4. Routing Module - Initialization

Irrespective of micro-apps, your app should have one starting point - main.js or index.js. In this file, you should initialize all your singleton things. Main singleton entities in a typical Vue.js app are Root Component, Data Store, Router, etc.

Your routing module will be separate from any component. Import routing module in this entry file and initialize it here.

5. Routing Module - Implementation

Routing module should be further split into smaller modules. Use simple functions and ES modules to do that. Each function will be responsible for returning a RouteConfig object. This is how it will look:

const route: RouteConfig = {
    path: '/some-path',
    component: AppComponent,
    children: [
        getWelcomeRoute(),
        getDashboardRoute()
    ]
};

function getWelcomeRoute(): RouteConfig {
    return {
        name: ROUTE_WELCOME,
        path: '',
        component: WelcomeComponent
    };
}

At route level, you should consider doing lazy loading of the modules. This will save many bytes from loading upfront:

function getLazyWelcomeRoute(): RouteConfig {

    // IMPORTANT for lazy loading
    const LazyWelcomeComponent = () => import('views/WelcomeComponent.vue');

    return {
        name: ROUTE_WELCOME,
        path: '',
        component: LazyWelcomeComponent
    };
}

You cannot do this unless you use bundler like Webpack or Rollup.

5. Routing Module - Guard

This is very important Guards are where you should handle your authorization. With Vue.js, it is possible to write component level route guard. But my suggestion is to refrain from doing so. Do it only when absolutely necessary. It is basically a separation of concern. Your routing module should possess the knowledge of authorization of your app. And technically, authorization exists/applies to a route than a component. That is the reason, why we created routing as a separate module altogether.

I am assuming that you are using some sort of data store like Redux or Vuex for the very large application. If you are going to write route level guards, then you will need to consult with data from Redux/Vuex store to take authorization decisions. It means you need to inject store into routing module. The simplest way to do that is to wrap your router initialization into a function like this:

export function makeRouter(store: Store<AppState>): VueRouter {
    // Now you can access store here
    return new VueRouter({
        mode: 'history',
        routes: [
            getWelcomeRoute(store),
        ]
    });
}

Now you can simply call this function from your entry-point file.

6. Routing Module - Default route

Remember to define a default catch-all route to show generic/intelligent 404 message to your users.

7. Routing Module - Routing data

Since we are really talking about very large application, it is better to avoid direct access to a router within your component. Instead, keep your router data in sync with your data store like vuex-router-sync . You will save the painful amount of bugs by doing this.

8. Routing Module - Side effects

You will often use $router.replace() or $router.push() within your components. From a component perspective, it is a side effect. Instead, handle programmatic router navigation outside of your component. Create a central place for all router navigation. Dispatch a request/action to this external entity to handle these side effects for you. TLDR; Don't do routing side effect directly within your components. It will make your components SOLID and easy to test. In our case, we use redux-observable to handle routing side effects.

I hope this covers all the aspects of routing for a very large scale application.

Jordain answered 15/5, 2018 at 18:39 Comment(2)
Hi, individual apps means you may have apps by module? That means you have to host the apps individually? If this is right how do you connect one app with the other in terms of routing and state management? ThanksPentup
@Pentup also a bit late, what he meant is that with Micro-Frontends, all frontend components are categorized into a sub set of categories. For example we have a landing page and a documentation page for services. We can host both of those into a single app provided they are isolated from one another. It is easier to manage this way. While also benefitting of shared resources like, common base css and availability of other helper methods via modules. Micro-Frontends does a better way of teaching this.Dionysiac
H
5

If you go with SPA app, please make sure you are using these practices:

  1. Lazy loading/async components. We usually do lazy loading for static assets. In the same spirit, we only need to load the components when the routes are visited. Vue will only trigger the factory function when the component needs to be rendered and will cache the result for future re-renders.
import MainPage from './routes/MainPage.vue'
const Page1 = r => require.ensure([], () => r(require('./routes/Page1.vue')))

const routes = [
  { path: '/main', component: MainPage },
  { path: '/page1', component: Page1 }
]
  1. Combining routes: (related to above) For example, in the following case, 2 routes are output in the same chunk and bundle, causing that bundle to be lazy-loaded when either route is accessed.
const Page1 = r => require.ensure([], () => r(require('./routes/Page1.vue')), 'big-pages')  
const Page2 = r => require.ensure([], () => r(require('./routes/Page2.vue')), 'big-pages')
Hopple answered 3/5, 2018 at 22:56 Comment(0)
E
1

Nuxt can help you with that. It generates your folder Structur dynamically to a router config file. Have a look at https://nuxtjs.org/guide/routing

It has even more help functions than routing. But especially for large applications in general an idea to set on nuxt

Ethiopic answered 8/5, 2018 at 8:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.