vue-router作为Vue官方三大套件之一,在日常开发中成为了不可或缺的存在,但是不管多么
niubility
的框架或组件,在业务场景不断发生改变的同时,不可避免的会出现一些适用性上的问题,这就需要我们去扩展不同的使用场景,以达到业务上的最佳实践。
vue-router使用姿势
按照vue-router官方的使用文档中,我们在配置和使用vue-router的姿势如下:
- 组件与路由的映射匹配
// router/index.js
const routes = [
{ path: '/home', component: Home },
{ path: '/about', component: About }
]
export default routes
- 挂载router
// main.js
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
import routes from './router/index.js'
const router = new VueRouter({
routes
});
new Vue({
el: '#app',
//让vue知道我们的路由规则
router: router,
render: c => c(App),
})
ok,现在我们就可以在我们的组件中通过this.$route
来操作路由相关属性及方法了。简直so easy!
vue-router的中心化问题
何为中心化?
谈到中心化,我们想到比较多的可能就是区块链
。那广义上的中心化如何理解?简单点说,就是在一个体系中某个节点要和另外的节点产生联系,就一定要通过特定的某个节点,这个节点就是一个中心。
vue-router的中心化
刚讲到中心化的概念,那我们可以拿上面vue-router实践的例子来对照一下。
我们在router/index.js
中定义或加载所有的路由配置,那这个文件就是这个项目当中唯一的引用路由的节点(中心)。那中心节点会存在什么问题呢?
- 文件冲突:尤其是在使用svn这种集中式版本控制服务,没有分支的概念,全部依赖一个远程中心仓库。
- 发布故障:试想多人同时修改同一个文件,在发布流程不是非常完善,且相互沟通不顺畅的情况下,容易出现某个正在开发的需求被另一个同样发布中的需求带上线了,但另一个需求的相关依赖并没有上线。导致生产环境编译错误从而引发线上故障。
下面我们用一个比较简单的发布模型来说明。
模拟开发场景:
- 2人同时开发一个项目。
- 2个需求分别新建了2个router配置。
- 现在2个需求都开发完了,准备继续后续的测试->发布流程。
PS: 上述的场景不一定发生,跟对应开发团队的发布流程相关。在开发流程比较完善的情况下是可以避免该问题的。
如何解决
- 模块化
- require.context
1. 模块化
可以将路由按业务模块划分场景,对应模块下有一个独立的入口文件,尽可能保证相同业务需求不会出现路由文件冲突的情况。
对应的加载路由的配置可以修改为
// moduleA/index.js
import routeA from './moduleA-xx'
import routeA2 from './moduleA-xx2'
// 在这里扩展moduleA的路由配置
const routes = [].concat(routeA, routeA2)
export default routes
// router/index.js
import moduleA from './moduleA/index'
import moduleB from './moduleB/index'
const routes = [].concat(moduleA, moduleB)
2. require.context
官方文档的说明是require.context
使用 directory 路径、includeSubdirs 选项和 filter 来指定一系列完整的依赖关系,便于更细粒度的控制模块引入。
文档地址:https://webpack.js.org/guides/dependency-management/#requirecontext
简单来说,通过require.context我们可以通过正则动态匹配并引入我们的依赖文件,这样我们不需要显示的去加载我们的路由文件,从而解耦router的入口文件和对应route配置的依赖关系。在这里我们通过它来实现我们的路由去中心化。
我们约定router目录下所有的.js文件默认都为route的配置文件,通过require.context加载的代码如下。
// 加载router目录下所有js文件作为路由配置
let routes
let matches = require.context('./', true, /^\.\/[^/]+\/.+\.js$/)
matches.keys().forEach(key => {
routes = routes.concat(matches(key).default)
})
这样,以后新增或修改路由只需要按照约定在router目录新建js文件或修改其中的配置即可,router/index.js
不需要任何改动即可完成路由配置。
总结
在这里我们总结下对于上述问题的一个解决思路,我们可以把中心化问题看成是一个依赖解耦的问题。那我们便可以用解耦的思路来解决中心化的问题,在上述解决方案中,我们用到了以下手段:
- 单一职责:模块化拆分路由配置。
- 依赖倒置:通过约定大于配置的方式将入口文件与路由配置细节解耦,将路由配置的显式加载过程抽象为通过
require.context
方式加载,具体的执行过程交由webpack在编译构建时去分析,从而解除依赖。
关于解耦的问题,我觉得也是一个可以好好讨论的点,有时间再和大家一起分享分享啦!感谢各位百忙之中抽出时间观看!!!