写在前面:

有的时候再做大型项目的时候,确实会被复杂的路由逻辑所烦恼,会经常遇到权限问题,路由跳转回退逻辑问题。这几天在网上看到了51信用卡团队开源了一个Miox,可以有效的解决这些痛点,于是乎我就做了一些尝试,确实很不错,star增速也表明了业界对其的认可!由于自己能力有限,不能很好地解读Miox,于是我就把Miox作者的文章给搬过来了,希望对大家有所帮着。(跟作者聊过之后,了解到作者团队开发了2年多,沉淀了很深,后来选择了开源,如果大家觉得好的话,可以去点一下star!)

github地址:GitHub: 51nb/Miox

文档地址: https://51nb.github.io/miox-doc/

Miox带你走进动态路由的世界

最近,我们团队开源了一套沉淀了2年的前端SPA架构框架,主要是用来解决动态路由的问题。我们的思路来源于后端,采用中间件的设计模式来架构整个框架。我们的原则是让大家快速开发一个SPA单页应用,只关心业务逻辑,其他的行为都可以帮助处理掉。

其实我们的开源比较匆忙,从很多方面看还是有些不标准的,但是之后我们会严格按照标准的规范和流程走下去,给大家一份稳定的架构。对于现在开始关注我们团队的小伙伴,我表示非常的感谢。有大家的支持,我们会做的更好。

Miox到底要解决什么问题?

这个问题从我们设计的初衷来说,就是解决所有路由的问题。在业界,其实大家都普遍认可一对一的路由模式,从而生产出了很多路由体系,比如vue-routerreact-router。他们都是非常不错的架构,从某种意义上来说,引领了前端路由的前进。很多小伙伴都是直接使用他们的全家桶来开发项目,也得到了很好的效果。

我不确定大家是否考虑过一个问题,当一个用户从登陆页面A登陆后进入B,再回到A页面的情况。一对一的静态路由其实理论上最终会将A页面显示为未登录,这是完全正确的,但是逻辑上它应该是一个登录的页面。静态路由无法区分环境变量对页面选择的影响,只能通过hook等手段来将页面内容替换掉。理论上,我们借助后端的写法应该是这样的逻辑:

  1. route.get('/a', ctx => {
  2. if (global.logined) {
  3. ctx.render(webveiwA);
  4. } else {
  5. ctx.render(webviewB);
  6. }
  7. })

  

我们需要根据周边的环境变量去自动选择该渲染哪个页面,如此的逻辑才是我们想要的。所以我们会根据这样的思路来设计动态路由。在nodejs的世界中,这种模式已经非常常见,比如express-routerkoa-router,都是采用这种设计思路来实现动态话的路由体系。我观察了前端的发展,都没有提出在前端实现这样的逻辑。于是,我们便开始研究如何将这种思路架设在前端使用,来获得更理想的逻辑体验。

Miox从来都不是依赖任何MVX框架来实现

为什么这么说呢?原因非常简单。在公司里面,我们大概有90%的H5业务都是采用Miox来实现的。我们的技术栈其实是Vue,因为Miox对Vue的结合太过深入,所以自然有部分小伙伴认为Miox是基于Vue来开发的,也就是说Miox是依赖着Vue?其实不是,Miox并不依赖任何框架实现。我来举个列子:

我们的电脑,如果换了一个显卡,那么必须要装显卡驱动。根据不同的显卡驱动,表现也不同。如果我们将Vue当作一个显卡,而Miox当作我们的电脑,那么我们需要一份显卡驱动来让整台电脑接受这块显卡。

所以我提出一个概念,就是渲染驱动的概念。Vue仅仅是我们Miox的一个渲染引擎,用来渲染页面的,可以理解为模板。我们还需要一份驱动告诉Miox,来说明Vue的渲染是如何在Miox实现的。这部分可以从这里看明白。当然,不仅仅是Vue,我们还能够将React接入到Miox中。理论上,只要能提供对应的渲染驱动,都可以将任意的渲染引擎接入到Miox中来使用。自然的,大家的书写都将会变成那种引擎的书写方式。这就是我们的插拔式设计。在公司里面使用的时候,我们不必在意使用何种渲染引擎,Miox都可以支持,同时帮您管理好整个路由体系。

基于中间件实现

在前端,如果我们能够用中间件来拦截整个逻辑过程的话,对开发是相当有利的,不仅仅在代码层面能够提高可读性,同时可以在具体业务层面提高效率。我们用后端路由逻辑来举个例子:

当我们遇到一些API都是需要经过登录验证的时候,我们可以将/authorize的路由前缀都使用中间件统一处理。其他的都不走验证逻辑。

  1. const Authorize = require('./auth');
  2. const AuthorizeApi = require('./auth/routes');
  3. route.use(
  4. '/authorize',
  5. Authorize.connect(), // Authorize.connect是统一的验证逻辑代码
  6. AuthorizeApi.routes(),
  7. AuthorizeApi.allowedMethods()
  8. );

  

如此当通过/authorize的路由都需要经过Authorize.connect()来验证是否具有权限。这使得代码非常简洁易懂。

Miox的设计便是如此,通过这种中间件的架构,使得我们在前端获得了统一拦截处理的能力。在实际生产中,我们很多地方都用到了中间件来处理统一的校验逻辑,使得代码维护性得到很大地提升。

那么如果不使用呢?我们需要在进入页面的时候,每个页面中都要嵌入一段代码来处理权限问题,不仅仅代码量增加,而且对于之后的维护,可能会产生漏改的问题。

具体想了解中间件的小伙伴,我推荐去看下koa-router

缓存页面得到更好的渲染性能

说到缓存,这个话题过于庞大,对于Miox的缓存机制,我只能简单介绍一下,有兴趣的小伙伴可以看下源码

在开发过程中,特别是对于开发移动端页面,我们需要保存前一个页面滚动位置,那么我们在切换到另一个页面的时候是不能将前一个页面销毁的,原因是我们希望回到前一个页面的时候还是停留在之前滚动的位置。那么我们需要缓存这个页面来确保位置的不改动。Miox模拟了history的部分API,同时增加了一层页面堆栈。我们需要维护这层页面堆栈来确保页面的可溯性。每次我们通过一种算法来动态比较路由与页面的关系,从而从这个堆栈中选出我们想要的缓存页面。当然,没有这个对应关系的时候,我们自然是要创建的。我们基于尽最大可能限度复用页面的宗旨,来缓存这些页面与路由的关系。

可能有人要问,如果缓存过多,对于页面的切换会有性能上的影响吧?是的,过多的页面缓存也是阻碍性能的关键。这里我们进行了缓存个数的优化。在启动miox服务的时候,我们有一个配置的参数max,一般默认为一个,当然,大家也可以自己自由设置最大个数,来保障缓存的性能问题。

历史遗留问题:history方向问题的解决方案

在History中,我们都承认无法判断出当前浏览器行为的方向性,所以无法给出我们想要的方向来自动做页面切换的效果。为了解决这个问题,我们搜集了业界的解决方案,采用sessionStorage来模拟history堆栈,从而解决这个问题(新history的API中已经增加了history.index动态属性来告诉我们现在位于堆栈中的位置)。我们将此方案整合到了Miox中,并且对其加强,来告诉动画引擎这次行为在浏览器中是如何表现的。自然,动画引擎就能够根据这个来自动切换页面的动画,达到自动处理的效果。

官方提供了一个简单的模块来支持动画,当然小伙伴想要自定义动画也是非常简单的,具体见这里

独立的页面生命周期

在传统的MVX框架中提供了组件的生命周期,我们在某种意义上也认为是页面的生命周期,但是我们对比原生IOS的周期行为,还是有所欠缺的。比如说active生命周期。这个是什么意思呢?我来举例说明:

当一个页面被推入后台,又被唤起的时候,我们根本不知道它是不是再一次被激活,我们只能知道页面又一次被进入,第二次进入的概念是需要很多代码来辅助完成的。而在传统框架中,很难触发再一次的mounted生命周期,因为页面已经被mounted过了。Miox提供了这样的生命周期的定义。

  1. // use vue.js
  2. export default Vue.extend({
  3. mounted() {
  4. this.$on('webview:active', this.activeLife);
  5. },
  6. methods: {
  7. activeLife() {
  8. console.log('我被唤起了');
  9. }
  10. }
  11. })

  

当然,我们也可以将这些生命周期直接抛到全局去,用于全局的监控。

  1. app.on('webview:mounted', webview => {
  2. console.log(webview);
  3. })

  

对于前置的生命周期,我们同样提供了以下的生命周期来辅助:

  • webview:enter
  • webview:leave
  • webview:beforeEnter
  • webview:beforeLeave

这些周期能够让你很好地掌控整个过程,对于自动埋点什么的功能非常实用。

服务端渲染

目前主流的架构都支持了服务端渲染来增强SEO的能力,那么对于Miox而言,也需要支持他们的服务端渲染。考虑到Miox自身会给渲染出来的内容包裹一些代码,所以,我们需要自己实现SSR。当然,渲染引擎的SSR实现是交给自己来完成的。也就是说我们需要给他包裹一层SSR渲染。

Miox暂时支持Vue的SSR渲染,后续会逐步添加对于React的SSR渲染。还有比如百度的san.js其实也可以接入进来实现SSR渲染。服务端渲染并不是太麻烦,如果大家能够掌握Miox的运行原理的话。

最后

对于开源,我们团队内部做了很多努力,也咨询了很多大牛,希望能够给大家创造出一份简易开发的架构来帮助大家完成业务。目前,团队后续计划如下:

  • 完善SSR的文档
  • 规范化Github上的git message
  • 维护Github上的Issues和PR
  • 单测和代码覆盖率增强
  • 对路由架构更多思考来完善Miox
  • 提供Pc端的演示demo
  • 提供Miox实际开发场景下的开发代码示例

希望大家看到这篇文章后可以支持我们,给我们多提供一些意见和建议,让我们共同将Miox完善下去。喜欢的小伙伴,帮忙点个Star。

项目开源在 GitHub: 51nb/Miox

出处:掘金专栏-51信用卡前端团队 https://juejin.im/post/5a0eee94f265da430702d8e0

Miox带你走进动态路由的世界——51信用卡前端团队的更多相关文章

  1. MYSQL(基本篇)——一篇文章带你走进MYSQL的奇妙世界

    MYSQL(基本篇)--一篇文章带你走进MYSQL的奇妙世界 MYSQL算是我们程序员必不可少的一份求职工具了 无论在什么岗位,我们都可以看到应聘要求上所书写的"精通MYSQL等数据库及优化 ...

  2. GDI+入门——带你走进Windows图形的世界

    一.GDI+基础 1.GDI+简单介绍 GDI+是微软的新一代二维图形系统,它全然面向对象,要在Windows窗口中显示字体或绘制图形必需要使用GDI+.GDI+提供了多种画笔.画刷.图像等图形对象, ...

  3. FL Studio带你走进混音的世界

    混音,是把多种音源整合到一个立体音轨或单音音轨中,通俗讲就是对多种声音进行调整后叠加在一起,这样可以让音乐听起来非常有层次感,尤其是在电音制作过程中,混音的质量更是起到了决定性的作用.音乐制作软件FL ...

  4. 一篇文章带你走进meta viewport的世界

    一.什么是 meta 标签? 可提供有关页面的元信息 二.为什么需要移动端适配? 因为我们在 pc 端上看到的页面都是比较大的,在 pc 端上都是正常显示的,自动不会被进行缩放,除非手动进行放大或缩小 ...

  5. Three.js - 走进3D的奇妙世界

    本文将通过Three.js的介绍及示例带我们走进3D的奇妙世界. 文章来源:宜信技术学院 & 宜信支付结算团队技术分享第6期-支付结算部支付研发团队前端研发高级工程师-刘琳<three. ...

  6. 从壹开始前后端分离 [ vue + .netcore 补充教程 ] 三十║ Nuxt实战:动态路由+同构

    上期回顾 说接上文<二九║ Nuxt实战:异步实现数据双端渲染>,昨天咱们通过项目二的首页数据处理,简单了解到了 nuxt 异步数据获取的作用,以及亲身体验了几个重要文件夹的意义,整篇文章 ...

  7. 小丁带你走进git的世界三-撤销修改

    一.撤销指令 git checkout还原工作区的功能 git reset  还原暂存区的功能 git clean  还没有被添加进暂存区的文件也就是git还没有跟踪的文件可以使用这个命令清除他们 g ...

  8. 小丁带你走进git的世界二-工作区暂存区分支

    小丁带你走进git的世界二-工作区暂存区分支 一.Git基本工作流程 1.初始化一个仓库 git  init git  clone git仓库分为两种情况: 第一种是在现有项目或目录下导入所有文件到 ...

  9. 小丁带你走进git世界一-git简单配置

    小丁带你走进git世界一-git简单配置 1.github的简单配置 配置提交代码的信息,例如是谁提交的代码之类的. git config  –global user.name BattleHeaer ...

随机推荐

  1. Microsoft dynamic sdk中join应该注意的问题.

    QueryExpression queryNextSeq = new QueryExpression { EntityName = "ep_prodoperationsequence&quo ...

  2. php的api及登录的权限验证

    类,库,接口(APi),函数,这些概念都是根据问题规模的大小来界定的.一个很小的问题肯定没有必要写成一个库,只需要写几句话就行了. 但是比如一个登录验证,这个功能很强大,很通用,可能前台后台都需要用到 ...

  3. 详解JavaScript对象继承方式

    一.对象冒充 其原理如下:构造函数使用 this 关键字给所有属性和方法赋值(即采用类声明的构造函数方式).因为构造函数只是一个函数,所以可使 Parent 构造函数成为 Children 的方法,然 ...

  4. 用Java语言实现简单的词法分析器

    编译原理中的词法分析算是很重要的一个部分,原理比较简单,不过网上大部分都是用C语言或者C++来编写,笔者近期在学习Java,故用Java语言实现了简单的词法分析器. 要分析的代码段如下: 输出结果如下 ...

  5. myeclipse的导航器

    在myeclipse的导航器下面可以看到编译后的文件目录结构 如何打开导航器试图呢? 窗口->显示视图->导航器 windows->show view->Navigator 这 ...

  6. react-native-image-picker 运用launchCamera直接调取摄像头的缺陷及修复

    在前几天用react-native进行android版本开发当中,用到了"react-native-image-picker"的插件:根据业务的需求:点击按钮-->直接调取摄 ...

  7. asp.net(C#)实现功能强大的时间日期处理类完整实例

    作者:smartsmile2012 字体:[增加 减小] 类型:转载 时间:2016-06-30我要评论 这篇文章主要介绍了asp.net(C#)实现功能强大的时间日期处理类,封装了针对日期与时间的各 ...

  8. Python基础数据类型之int、bool、str

    数据类型:int  bool  str  list  元祖  dict  集合 int:整数型,用于各种数学运算. bool:只有两种,True和False,用户判断. str:存储少量数据,进行操作 ...

  9. 翻译:JVM虚拟机规范1.7中的运行时常量池部分(三)

    4.4.7. The CONSTANT_Utf8_info Structure The CONSTANT_Utf8_info structure is used to represent consta ...

  10. 在删除一个指针之后,一定将该指针设置成空指针(即在delete *p之后一定要加上: p=NULL)

    在删除一个指针之后,一定将该指针设置成空指针(即在delete *p之后一定要加上: p=NULL)