非常庞大的Web应用程序中使用Vue-Router的最佳实践是什么?

38

我需要制作一个包含许多不同模块的Web应用程序(例如待办事项模块、文档模块和一个大型的管理员用户管理模块)。总页面数大于100,并且每个用户的模块访问权限不同。

我正在使用 Laravel 和 Vue-router。

但是做这件事的最佳实践是什么呢?

  1. 创建一个 SPA 应用程序,使用 1 个大的 vue-router 处理所有内容?
  2. 为每个模块创建单独的 "SPA"(拥有自己的 vue-router)?
  3. 还有其他建议吗...?

让我们来讨论一下:当使用多个路由器时,频繁切换模块是否会导致速度变慢? - online Thomas
嘿,angelique000,我在参考我们使用Vue.js构建大型JS应用程序的方式后更新了答案。请告诉我它是否对你有所帮助。 - Harshal Patil
3个回答

39

虽然有些晚,但我会尝试回答这个问题。这更多是一个架构问题,而不仅仅是路由级别的问题。

TLDR:你需要采用多种方法,不能只用一种方法。

1. 路由模式

首先,你应该确定是否使用HTML 5历史模式或哈希模式。现在是2018年,我强烈建议你使用HTML5历史模式。

如果你使用历史模式,那么意味着你的客户端路由器需要与服务器端路由器同步工作。

2. 微前端

我不知道你是否知道这个术语,但微前端就是你正在寻找的术语。基本上,它是你的第一行分离。你应该将你的应用程序拆分成多个较小的应用程序。每个应用程序都有自己的根组件、路由器、模型、服务等。你将共享许多组件(当然,这里非常大的应用程序很重要。我真的是这个意思)。

3. 单一存储库考虑

如果你决定使用微前端,那么你可能会考虑单一存储库设置,使用Lerna或Builder。

4. 路由模块 - 初始化

无论微应用程序如何,你的应用程序都应该有一个起点:main.jsindex.js。在这个文件中,你应该初始化所有单例事物。典型Vue.js应用程序中的主要单例实体包括根组件数据存储路由器等。

你的路由模块将与任何组件分开。在这个入口文件中导入路由模块并在此处初始化它。

5. 路由模块 - 实现

路由模块应该进一步拆分成较小的模块。使用简单的函数和ES模块来完成。每个函数将负责返回一个RouteConfig对象。它看起来像这样:

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

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

在路由级别上,你应该考虑对模块进行惰性加载。这样可以节省很多要一开始加载的字节:

function getLazyWelcomeRoute(): RouteConfig {

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

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

如果你不使用类似Webpack或Rollup这样的打包工具,那么你无法做到这一点。

5. 路由模块 - 守卫

这非常重要守卫是你处理授权的地方。在Vue.js中,你可以编写组件级别的路由守卫。但我的建议是尽量不要这样做。只有在绝对必要的情况下才这样做。这基本上是责任分离。你的路由模块应该拥有你的应用程序授权的知识。从技术上讲,授权存在/适用于路由而不是组件。这就是我们将路由创建为一个单独的模块的原因。

我假设你正在使用Redux或Vuex等数据存储库来开发大型应用程序。如果你要编写路由级别的守卫,则需要查看Redux/Vuex存储库中的数据以进行授权决策。这意味着你需要将存储库注入到路由模块中。最简单的方法是将路由器初始化包装成如下函数:

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

现在,您可以从入口文件中简单地调用此函数。

6. 路由模块 - 默认路由

请记得定义一个默认的通用捕获所有路由,以向用户展示智能的404信息。

7. 路由模块 - 路由数据

由于我们正在讨论 非常大规模的 应用程序,因此最好避免在组件内直接访问路由器。相反,将路由器数据与数据存储(例如 vuex-router-sync )同步。这样做可以避免痛苦的错误。

8. 路由模块 - 副作用

您经常会在组件之间使用$router.replace()$router.push()。从组件的角度来看,这是一个副作用。相反,在组件外部处理编程式路由导航。创建一个集中的位置来处理所有路由导航。向此外部实体发送请求 / 操作以为您处理这些副作用。TLDR; 不要直接在组件内进行路由副作用。这将使您的组件SOLID并易于测试。在我们的情况下,我们使用redux-observable来处理路由副作用。

希望这涵盖了对于一个非常大规模的应用程序的所有路由方面。


你好,个人应用程序意味着您可能按模块拥有应用程序?这意味着您必须单独托管应用程序?如果是这样,如何通过路由和状态管理将一个应用程序连接到另一个应用程序?谢谢。 - VAAA
@VAAA 也晚了一点,他的意思是使用微前端,所有前端组件都被归类为子集类别。例如,我们为服务拥有一个“登陆页面”和一个“文档页面”。只要它们相互隔离,我们就可以将它们两个托管到单个应用程序中。这样管理起来更容易。同时还可以从共享资源中受益,如公共基础 CSS 和通过模块可用的其他辅助方法。Micro-Frontends 更好地教授了这种方法。 - Dale Ryan

5

如果您选择使用SPA应用程序,请确保遵循以下最佳实践:

  1. 延迟加载/异步组件。我们通常对静态资源进行延迟加载。出于同样的原因,我们只需要在访问路由时加载组件。Vue仅在需要呈现组件时触发工厂函数,并将结果缓存以供将来重新呈现。
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 }
]
  • 路由组合:(与上面相关)例如,在下面的情况下,2个路由在同一个代码块和捆绑包中输出,当任一路由被访问时,导致该捆绑包进行懒加载。
  • const Page1 = r => require.ensure([], () => r(require('./routes/Page1.vue')), 'big-pages')  
    const Page2 = r => require.ensure([], () => r(require('./routes/Page2.vue')), 'big-pages')
    

    1
    Nuxt可以帮助您实现此目标。它将您的文件夹结构动态生成为路由配置文件。请查看https://nuxtjs.org/guide/routing
    它甚至比路由更具有辅助功能。但对于大型应用程序而言,选择使用nuxt是一个很好的主意。

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接